]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] all: merge master (2725522) into dev.typeparams
authorCherry Mui <cherryyz@google.com>
Tue, 1 Jun 2021 18:58:52 +0000 (14:58 -0400)
committerCherry Mui <cherryyz@google.com>
Tue, 1 Jun 2021 18:58:52 +0000 (14:58 -0400)
Merge List:

+ 2021-06-01 272552275f A+C: update name
+ 2021-06-01 2bec019fb5 doc/go1.17: add release notes for register ABI
+ 2021-06-01 2e59cc5fb4 cmd/go: add [-src] to documentation
+ 2021-06-01 0b80cf1136 cmd/go: make 'go get' save sums for incidentally updated modules
+ 2021-05-30 3b770f2ccb go/types: don't declare 'comparable' when typeparams are disabled
+ 2021-05-30 1607c28172 go/types: unexport the GoVersion configuration option for Go 1.17
+ 2021-05-29 79bda65041 doc/go1.17: mention time.Layout
+ 2021-05-29 f6cc392d1d doc/go1.17: document text/template/parse.SkipFuncCheck
+ 2021-05-28 1419ca7cea doc/go1.17: mention new definitions of MSG_CMSG_CLOEXEC
+ 2021-05-28 6624771c83 doc/go1.17: mention testing.[TB].Setenv methods
+ 2021-05-28 bbda923592 doc/go1.17: mention new Windows SysProcAttr fields
+ 2021-05-28 6f58088bd8 doc/go1.17: document new go/build/BuildContext.ToolTags field
+ 2021-05-28 c295107708 doc/go1.17: mention new encoding/csv/Reader.FieldPos method
+ 2021-05-28 ccd9784edf doc/go1.17: document new debug/elf constant
+ 2021-05-28 3de3440fb9 go/ast: remove FuncDecl.IsMethod for Go 1.17
+ 2021-05-27 639acdc833 doc/go1.17: clarify that compress/lzw Reader and Writer types are new
+ 2021-05-27 193d514131 net/http: correct Client.Do doc about context cancelation
+ 2021-05-27 ab2ef4aaa7 doc/go1.17: document reflect changes
+ 2021-05-27 0ece95a0fe cmd/go: don't let 'go mod download' save sums for inconsistent requirements
+ 2021-05-27 cdcd02842d net: verify results from Lookup* are valid domain names
+ 2021-05-27 8bf5bf5173 cmd/compile: improve debug locations for partially live in-params
+ 2021-05-27 56af34f875 cmd/compile: place reg spills after OpArg{Int,Float}Reg ops
+ 2021-05-27 db66e9e15d cmd/link: accept Windows line-ending in TestTrampolineCgo
+ 2021-05-27 6b8c94b6c5 go/types: guard against check==nil in newNamed
+ 2021-05-27 fca7b8f3e6 Revert "net: verify results from Lookup* are valid domain names"
+ 2021-05-27 950fa11c4c net/http/httputil: always remove hop-by-hop headers
+ 2021-05-27 9bc52686da cmd/go,cmd/link: do not check for staleness in most tests
+ 2021-05-27 6ff0ae2aa4 crypto/elliptic: fix typo in p521Point type name
+ 2021-05-26 3075ffc93e os: deflake TestFdReadRace
+ 2021-05-26 a62c08734f src/os: revert accidentally submitted change
+ 2021-05-26 1d5298d46a doc/go1.17: document net/... changes
+ 2021-05-26 0fbecece98 doc/go1.17: document syscall changes
+ 2021-05-26 02beecb397 mime: document use of the Shared MIME-Info Database
+ 2021-05-26 a92460fd2f doc/go1.17: add release notes for runtime/metrics package
+ 2021-05-26 55aefbb268 doc/go1.17: mention enabling frame pointer on all ARM64
+ 2021-05-26 39da9ae513 go/types: ensure that Named.check is nilled out once it is expanded
+ 2021-05-26 bfd7798a6c runtime,cmd/link/internal/ld: fix typos
+ 2021-05-26 e4615ad74d math/big: move division into natdiv.go
+ 2021-05-26 d050238bb6 doc/go1.17: fix formatting for time changes
+ 2021-05-25 74242baa41 archive/zip: only preallocate File slice if reasonably sized

Change-Id: I8a02edee1a6889547c52aa28c53cf8250766ab2c

46 files changed:
AUTHORS
CONTRIBUTORS
doc/go1.17.html
src/archive/zip/reader.go
src/archive/zip/reader_test.go
src/cmd/compile/internal/ssa/debug.go
src/cmd/compile/internal/ssa/regalloc.go
src/cmd/go/alldocs.go
src/cmd/go/internal/doc/doc.go
src/cmd/go/internal/modcmd/download.go
src/cmd/go/internal/modget/get.go
src/cmd/go/internal/modload/init.go
src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt [deleted file]
src/cmd/go/testdata/script/cgo_stale.txt [new file with mode: 0644]
src/cmd/go/testdata/script/list_std_stale.txt [deleted file]
src/cmd/go/testdata/script/list_std_vendor.txt [new file with mode: 0644]
src/cmd/go/testdata/script/mod_download.txt
src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_race_install_cgo.txt
src/cmd/go/testdata/script/toolexec.txt
src/cmd/link/dwarf_test.go
src/cmd/link/internal/ld/data.go
src/cmd/link/link_test.go
src/crypto/elliptic/p521.go
src/go/ast/ast.go
src/go/types/api.go
src/go/types/check.go
src/go/types/check_test.go
src/go/types/decl.go
src/go/types/resolver.go
src/go/types/sanitize.go
src/go/types/stdlib_test.go
src/go/types/type.go
src/go/types/types_test.go
src/go/types/universe.go
src/math/big/arith.go
src/math/big/nat.go
src/math/big/natdiv.go [new file with mode: 0644]
src/mime/type.go
src/net/dnsclient_unix_test.go
src/net/http/client.go
src/net/http/httputil/reverseproxy.go
src/net/http/httputil/reverseproxy_test.go
src/net/lookup.go
src/os/pipe_test.go
src/runtime/malloc.go

diff --git a/AUTHORS b/AUTHORS
index 48ce71f4cc6bc8088bf9f013c25b3673defe1a70..95d3158d204ff0cc73238867aeba27e0d70b0e34 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -41,7 +41,7 @@ Aeneas Rekkas (arekkas) <aeneas@ory.am>
 Afanasev Stanislav <phpprogger@gmail.com>
 Agis Anastasopoulos <agis.anast@gmail.com>
 Agniva De Sarker <agnivade@yahoo.co.in>
-Ahmed Wahed <oneofone@gmail.com>
+Ahmed W. Mones <oneofone@gmail.com>
 Ahmet Soormally <ahmet@mangomm.co.uk>
 Ahmy Yulrizka <yulrizka@gmail.com>
 Aiden Scandella <ai@uber.com>
index 6c7262adb1ffda7ccab4e3cda8c7f929925b53f0..ee50a4c049aa674aa400b6ab99871438c53d37a9 100644 (file)
@@ -67,7 +67,7 @@ Aeneas Rekkas (arekkas) <aeneas@ory.am>
 Afanasev Stanislav <phpprogger@gmail.com>
 Agis Anastasopoulos <agis.anast@gmail.com>
 Agniva De Sarker <agnivade@yahoo.co.in>
-Ahmed Wahed <oneofone@gmail.com>
+Ahmed W. Mones <oneofone@gmail.com>
 Ahmet Alp Balkan <ahmetb@google.com>
 Ahmet Soormally <ahmet@mangomm.co.uk>
 Ahmy Yulrizka <yulrizka@gmail.com>
index c2317a4035284d21e8194c903a7c0f565ec3b55d..ee498f76035ce1b72617fb5d7f886385cd2d8e08 100644 (file)
@@ -68,6 +68,14 @@ Do not send CLs removing the interior tags from such phrases.
   OpenBSD.
 </p>
 
+<h3 id="arm64">ARM64</h3>
+
+<p><!-- CL 288814 -->
+  Go programs now maintain stack frame pointers on the 64-bit ARM
+  architecture on all operating systems. Previously it maintained
+  stack frame pointers only on Linux, macOS, and iOS.
+</p>
+
 <p>
   TODO: complete the Ports section
 </p>
@@ -218,31 +226,57 @@ Do not send CLs removing the interior tags from such phrases.
 
 <h2 id="runtime">Runtime</h2>
 
-<p><!-- CL 304470 -->
-  TODO: <a href="https://golang.org/cl/304470">https://golang.org/cl/304470</a>: cmd/compile, runtime: add metadata for argument printing in traceback
-</p>
-
 <p>
   TODO: complete the Runtime section
 </p>
 
 <h2 id="compiler">Compiler</h2>
 
-<p><!-- CL 283112, golang.org/issue/28727 -->
+<p><!-- golang.org/issue/40724 -->
+  Go 1.17 implements a new way of passing function arguments and results using
+  registers instead of the stack. This work is enabled for Linux, MacOS, and
+  Windows on the 64-bit x86 architecture (the <code>linux/amd64</code>,
+  <code>darwin/amd64</code>, <code>windows/amd64</code> ports). For a
+  representative set of Go  packages and programs, benchmarking has shown
+  performance improvements of about 5%, and a typical reduction in binary size
+  of about 2%.
+</p>
+
+<p>
+  This change does not affect the functionality of any safe Go code. It can affect
+  code outside the <a href="/doc/go1compat">compatibility guidelines</a> with
+  minimal impact. To maintain compatibility with existing assembly functions,
+  adapter functions converting between the new register-based calling convention
+  and the previous stack-based calling convention (also known as ABI wrappers)
+  are sometimes used. This is mostly invisible to users, except for assembly
+  functions that have their addresses taken in Go. Using <code>reflect.ValueOf(fn).Pointer()</code>
+  (or similar approaches such as via <code>unsafe.Pointer</code>) to get the address
+  of an assembly function will now return the address of the ABI wrapper. This is
+  mostly harmless, except for special-purpose assembly code (such as accessing
+  thread-local storage or requiring a special stack alignment). Assembly functions
+  called indirectly from Go via <code>func</code> values will now be made through
+  ABI wrappers, which may cause a very small performance overhead. Also, calling
+  Go functions from assembly may now go through ABI wrappers, with a very small
+  performance overhead.
+</p>
+
+<p><!-- CL 304470 -->
+  The format of stack traces from the runtime (printed when an uncaught panic
+  occurs, or when <code>runtime.Stack</code> is called) is improved. Previously,
+  the function arguments were printed as hexadecimal words based on the memory
+  layout. Now each argument in the source code is printed separately, separated
+  by commas. Aggregate-typed (struct, array, string, slice, interface, and complex)
+  arguments are delimited by curly braces. A caveat is that the value of an
+  argument that only lives in a register and is not stored to memory may be
+  inaccurate. Results (which were usually inaccurate) are no longer printed.
+</p>
 
+<p><!-- CL 283112, golang.org/issue/28727 -->
   Functions containing closures can now be inlined. One effect of this change is
   that a function with a closure may actually produce a distinct closure function
   for each place that the function is inlined. Hence, this change could reveal
   bugs where Go functions are compared (incorrectly) by pointer value. Go
   functions are by definition not comparable.
-
-  TODO: complete the Compiler section, or delete if not needed
-</p>
-
-<h2 id="linker">Linker</h2>
-
-<p>
-  TODO: complete the Linker section, or delete if not needed
 </p>
 
 <h2 id="library">Core library</h2>
@@ -323,11 +357,16 @@ Do not send CLs removing the interior tags from such phrases.
 <dl id="compress/lzw"><dt><a href="/pkg/compress/lzw/">compress/lzw</a></dt>
   <dd>
     <p><!-- CL 273667 -->
-      The new
-      <a href="/pkg/compress/lzw/#Reader.Reset"><code>Reader.Reset</code></a>
-      and
-      <a href="/pkg/compress/lzw/#Writer.Reset"><code>Writer.Reset</code></a>
-      methods allow reuse of a <code>Reader</code> or <code>Writer</code>.
+      The <a href="/pkg/compress/lzw/#NewReader"><code>NewReader</code></a>
+      function is guaranteed to return a value of the new
+      type <a href="/pkg/compress/lzw/#Reader"><code>Reader</code></a>,
+      and similarly <a href="/pkg/compress/lzw/#NewWriter"><code>NewWriter</code></a>
+      is guaranteed to return a value of the new
+      type <a href="/pkg/compress/lzw/#Writer"><code>Writer</code></a>.
+      These new types both implement a <code>Reset</code> method
+      (<a href="/pkg/compress/lzw/#Reader.Reset"><code>Reader.Reset</code></a>,
+      <a href="/pkg/compress/lzw/#Writer.Reset"><code>Writer.Reset</code></a>)
+      that allows reuse of the <code>Reader</code> or <code>Writer</code>.
     </p>
   </dd>
 </dl><!-- compress/lzw -->
@@ -360,6 +399,15 @@ Do not send CLs removing the interior tags from such phrases.
   </dd>
 </dl><!-- database/sql -->
 
+<dl id="debug/elf"><dt><a href="/pkg/debug/elf/">debug/elf</a></dt>
+  <dd>
+    <p><!-- CL 239217 -->
+      The <a href="/pkg/debug/elf/#SHT_MIPS_ABIFLAGS"><code>SHT_MIPS_ABIFLAGS</code></a>
+      constant has been added.
+    </p>
+  </dd>
+</dl><!-- debug/elf -->
+
 <dl id="encoding/binary"><dt><a href="/pkg/encoding/binary/">encoding/binary</a></dt>
   <dd>
     <p><!-- CL 299531 -->
@@ -371,6 +419,18 @@ Do not send CLs removing the interior tags from such phrases.
   </dd>
 </dl><!-- encoding/binary -->
 
+<dl id="encoding/csv"><dt><a href="/pkg/encoding/csv/">encoding/csv</a></dt>
+  <dd>
+    <p><!-- CL 291290 -->
+      The new
+      <a href="/pkg/encoding/csv/#Reader.FieldPos"><code>Reader.FieldPos</code></a>
+      method returns the line and column corresponding to the start of
+      a given field in the record most recently returned by
+      <a href="/pkg/encoding/csv/#Reader.Read"><code>Read</code></a>.
+    </p>
+  </dd>
+</dl><!-- encoding/csv -->
+
 <dl id="flag"><dt><a href="/pkg/flag/">flag</a></dt>
   <dd>
     <p><!-- CL 271788 -->
@@ -379,6 +439,17 @@ Do not send CLs removing the interior tags from such phrases.
   </dd>
 </dl><!-- flag -->
 
+<dl id="go/build"><dt><a href="/pkg/go/build/">go/build</a></dt>
+  <dd>
+    <p><!-- CL 310732 -->
+      The new
+      <a href="/pkg/go/build/#Context.ToolTags"><code>Context.ToolTags</code></a>
+      field holds the build tags appropriate to the current Go
+      toolchain configuration.
+    </p>
+  </dd>
+</dl><!-- go/build -->
+
 <dl id="io/fs"><dt><a href="/pkg/io/fs/">io/fs</a></dt>
   <dd>
     <p><!-- CL 293649 -->
@@ -400,7 +471,9 @@ Do not send CLs removing the interior tags from such phrases.
 <dl id="mime"><dt><a href="/pkg/mime/">mime</a></dt>
   <dd>
     <p><!-- CL 305230 -->
-      TODO: <a href="https://golang.org/cl/305230">https://golang.org/cl/305230</a>: support reading shared mime-info database on unix systems
+      On Unix systems, the table of MIME types is now read from the local system's
+      <a href="https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-0.21.html">Shared MIME-info Database</a>
+      when available.
     </p>
   </dd>
 </dl><!-- mime -->
@@ -408,15 +481,20 @@ Do not send CLs removing the interior tags from such phrases.
 <dl id="net"><dt><a href="/pkg/net/">net</a></dt>
   <dd>
     <p><!-- CL 272668 -->
-      TODO: <a href="https://golang.org/cl/272668">https://golang.org/cl/272668</a>: add IP.IsPrivate
+      The new method <a href="/pkg/net/#IP.IsPrivate"><code>IP.IsPrivate</code></a> reports whether an address is
+      a private IPv4 address according to <a href="http://tools.ietf.org/html/rfc1918">RFC 1918</a>
+      or a local IPv6 address according <a href="http://tools.ietf.org/html/rfc4193">RFC 4193</a>.
     </p>
 
     <p><!-- CL 301709 -->
-      TODO: <a href="https://golang.org/cl/301709">https://golang.org/cl/301709</a>: make go resolver aware of network parameter
+      The Go DNS resolver now only sends one DNS query when resolving an address for an IPv4-only or IPv6-only network,
+      rather than querying for both address families.
     </p>
 
     <p><!-- CL 307030 -->
-      TODO: <a href="https://golang.org/cl/307030">https://golang.org/cl/307030</a>: make ErrClosed and ParseError implement net.Error
+      The <a href="/pkg/net/#ErrClosed"><code>ErrClosed</code></a> sentinel error and
+      <a href="/pkg/net/#ParseError"><code>ParseError</code></a> error type now implement
+      the <a href="/pkg/net/#Error"><code>net.Error</code></a> interface.
     </p>
   </dd>
 </dl><!-- net -->
@@ -431,7 +509,9 @@ Do not send CLs removing the interior tags from such phrases.
     </p>
 
     <p><!-- CL 235437 -->
-      TODO: <a href="https://golang.org/cl/235437">https://golang.org/cl/235437</a>: add to deadlines only when positive
+      Setting the <a href="/pkg/net/http/#Server"><code>Server</code></a>
+      <code>ReadTimeout</code> or <code>WriteTimeout</code> fields to a negative value now indicates no timeout
+      rather than an immediate timeout.
     </p>
 
     <p><!-- CL 308952 -->
@@ -444,7 +524,10 @@ Do not send CLs removing the interior tags from such phrases.
 <dl id="net/http/httptest"><dt><a href="/pkg/net/http/httptest/">net/http/httptest</a></dt>
   <dd>
     <p><!-- CL 308950 -->
-      TODO: <a href="https://golang.org/cl/308950">https://golang.org/cl/308950</a>: panic on non-3 digit (XXX) status code in Recorder.WriteHeader
+      <a href="/pkg/net/http/httptest/#ResponseRecorder.WriteHeader"><code>ResponseRecorder.WriteHeader></code></a>
+      now panics when the provided code is not a valid three-digit HTTP status code.
+      This matches the behavior of <a href="/pkg/net/http/#ResponseWriter"><code>ResponseWriter></code></a>
+      implementations in the <a href="/pkg/net/http/"><code>net/http</code></a> package.
     </p>
   </dd>
 </dl><!-- net/http/httptest -->
@@ -452,7 +535,8 @@ Do not send CLs removing the interior tags from such phrases.
 <dl id="net/url"><dt><a href="/pkg/net/url/">net/url</a></dt>
   <dd>
     <p><!-- CL 314850 -->
-      TODO: <a href="https://golang.org/cl/314850">https://golang.org/cl/314850</a>: add Values.Has
+      The new method <a href="/pkg/net/url/#Values.Has"><code>Values.Has</code></a>
+      reports whether a query parameter is set.
     </p>
   </dd>
 </dl><!-- net/url -->
@@ -479,15 +563,27 @@ Do not send CLs removing the interior tags from such phrases.
     </p>
 
     <p><!-- CL 281233 -->
-      TODO: <a href="https://golang.org/cl/281233">https://golang.org/cl/281233</a>: add VisibleFields function
+      The new <a href="/pkg/reflect/#VisibleFields"><code>VisibleFields</code></a> function
+      returns all the visible fields in a struct type, including fields inside anonymous struct members.
     </p>
 
     <p><!-- CL 284136 -->
-      TODO: <a href="https://golang.org/cl/284136">https://golang.org/cl/284136</a>: panic if ArrayOf is called with negative length
+      The <a href="/pkg/reflect/#ArrayOf"><code>ArrayOf</code></a> function now panics when
+      called with a negative length.
     </p>
   </dd>
 </dl><!-- reflect -->
 
+<dl id="runtime/metrics"><dt><a href="/pkg/runtime/metrics">runtime/metrics</a></dt>
+  <dd>
+    <p><!-- CL 308933, CL 312431, CL 312909 -->
+      New metrics were added that track total bytes and objects allocated and freed.
+      A new metric tracking the distribution of goroutine scheduling latencies was
+      also added.
+    </p>
+  </dd>
+</dl><!-- runtime/metrics -->
+
 <dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
   <dd>
     <p><!-- CL 170079 -->
@@ -530,11 +626,30 @@ Do not send CLs removing the interior tags from such phrases.
 <dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
   <dd>
     <p><!-- CL 295371 -->
-      TODO: <a href="https://golang.org/cl/295371">https://golang.org/cl/295371</a>: do not overflow key memory in GetQueuedCompletionStatus
+    <p>
+      The <a href="/pkg/syscall/#GetQueuedCompletionStatus"><code>GetQueuedCompletionStatus</code></a> and
+      <a href="/pkg/syscall/#PostQueuedCompletionStatus"><code>PostQueuedCompletionStatus</code></a>
+      functions are now deprecated. These functions have incorrect signatures and are superseded by
+      equivalents in the <a href="https://godoc.org/golang.org/x/sys/windows"><code>golang.org/x/sys/windows</code></a> package.
     </p>
 
     <p><!-- CL 313653 -->
-      TODO: <a href="https://golang.org/cl/313653">https://golang.org/cl/313653</a>: restore signal mask after setting foreground process group
+      On Unix-like systems, the process group of a child process is now set with signals blocked.
+      This avoids sending a <code>SIGTTOU</code> to the child when the parent is in a background process group.
+    </p>
+
+    <p><!-- CL 288298, CL 288300 -->
+      The Windows version of
+      <a href="/pkg/syscall/#SysProcAttr"><code>SysProcAttr</code></a>
+      has two new fields. <code>AdditionalInheritedHandles</code> is
+      a list of additional handles to be inherited by the new child
+      process. <code>ParentProcess</code> permits specifying the
+      parent process of the new process.
+
+    <p><!-- CL 311570 -->
+      The constant <code>MSG_CMSG_CLOEXEC</code> is now defined on
+      DragonFly and all OpenBSD systems (it was already defined on
+      some OpenBSD systems and all FreeBSD, NetBSD, and Linux systems).
     </p>
   </dd>
 </dl><!-- syscall -->
@@ -544,13 +659,22 @@ Do not send CLs removing the interior tags from such phrases.
     <p><!-- CL 310033 -->
       TODO: <a href="https://golang.org/cl/310033">https://golang.org/cl/310033</a>: add -shuffle=off|on|N to alter the execution order of tests and benchmarks
     </p>
+
+    <p><!-- CL 260577 -->
+      The new
+      <a href="/pkg/testing/#T.Setenv"><code>T.Setenv</code></a>
+      and <a href="/pkg/testing/#B.Setenv"><code>B.Setenv</code></a>
+      methods support setting an environment variable for the duration
+      of the test or benchmark.
+    </p>
   </dd>
 </dl><!-- testing -->
 
 <dl id="text/template/parse"><dt><a href="/pkg/text/template/parse/">text/template/parse</a></dt>
   <dd>
     <p><!-- CL 301493 -->
-      TODO: <a href="https://golang.org/cl/301493">https://golang.org/cl/301493</a>: add a mode to skip func-check on parsing
+      The new <a href="/pkg/text/template/parse/#Mode"><code>SkipFuncCheck</code></a> <a href=><code>Mode</code></a>
+      value changes the template parser to not verify that functions are defined.
     </p>
   </dd>
 </dl><!-- text/template/parse -->
@@ -558,9 +682,10 @@ Do not send CLs removing the interior tags from such phrases.
 <dl id="time"><dt><a href="/pkg/time/">time</a></dt>
   <dd>
     <p><!-- CL 260858 -->
-      time.Time now has a <a href="/pkg/time/#Time.GoString">GoString</a>
-      method that will return a more useful value for times when printed with
-      the <code>"%#v"</code> format specifier in the fmt package.
+      The <a href="/pkg/time/#Time"><code>Time</code></a> type now has a
+      <a href="/pkg/time/#Time.GoString"><code>GoString</code></a> method that
+      will return a more useful value for times when printed with the
+      <code>%#v</code> format specifier in the <code>fmt</code> package.
     </p>
 
     <p><!-- CL 264077 -->
@@ -574,6 +699,11 @@ Do not send CLs removing the interior tags from such phrases.
     <p><!-- CL 300996 -->
       TODO: <a href="https://golang.org/cl/300996">https://golang.org/cl/300996</a>: support &#34;,&#34; as separator for fractional seconds
     </p>
+
+    <p><!-- CL 320252 -->
+      The new constant <a href="/pkg/time/#Layout"><code>Layout</code></a>
+      defines the reference time.
+    </p>
   </dd>
 </dl><!-- time -->
 
index 808cf274caddb3883f77863288976c383b710553..2d53f4c7231653d651b4f3b5bb1a15325b4a33ac 100644 (file)
@@ -96,7 +96,15 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
                return err
        }
        z.r = r
-       z.File = make([]*File, 0, end.directoryRecords)
+       // Since the number of directory records is not validated, it is not
+       // safe to preallocate z.File without first checking that the specified
+       // number of files is reasonable, since a malformed archive may
+       // indicate it contains up to 1 << 128 - 1 files. Since each file has a
+       // header which will be _at least_ 30 bytes we can safely preallocate
+       // if (data size / 30) >= end.directoryRecords.
+       if (uint64(size)-end.directorySize)/30 >= end.directoryRecords {
+               z.File = make([]*File, 0, end.directoryRecords)
+       }
        z.Comment = end.comment
        rs := io.NewSectionReader(r, 0, size)
        if _, err = rs.Seek(int64(end.directoryOffset), io.SeekStart); err != nil {
index 35e681ec6995e844540df7d5b30475e62a64e350..37dafe6c8e7c448c8fa28359e07fc2cdbb73560f 100644 (file)
@@ -1325,3 +1325,62 @@ func TestReadDataDescriptor(t *testing.T) {
                })
        }
 }
+
+func TestCVE202133196(t *testing.T) {
+       // Archive that indicates it has 1 << 128 -1 files,
+       // this would previously cause a panic due to attempting
+       // to allocate a slice with 1 << 128 -1 elements.
+       data := []byte{
+               0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08,
+               0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02,
+               0x03, 0x62, 0x61, 0x65, 0x03, 0x04, 0x00, 0x00,
+               0xff, 0xff, 0x50, 0x4b, 0x07, 0x08, 0xbe, 0x20,
+               0x5c, 0x6c, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00,
+               0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00,
+               0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0xbe, 0x20, 0x5c, 0x6c, 0x09, 0x00,
+               0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x01, 0x02, 0x03, 0x50, 0x4b, 0x06, 0x06, 0x2c,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d,
+               0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0x31, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x50, 0x4b, 0x06, 0x07, 0x00,
+               0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50,
+               0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0x00, 0x00,
+       }
+       _, err := NewReader(bytes.NewReader(data), int64(len(data)))
+       if err != ErrFormat {
+               t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat)
+       }
+
+       // Also check that an archive containing a handful of empty
+       // files doesn't cause an issue
+       b := bytes.NewBuffer(nil)
+       w := NewWriter(b)
+       for i := 0; i < 5; i++ {
+               _, err := w.Create("")
+               if err != nil {
+                       t.Fatalf("Writer.Create failed: %s", err)
+               }
+       }
+       if err := w.Close(); err != nil {
+               t.Fatalf("Writer.Close failed: %s", err)
+       }
+       r, err := NewReader(bytes.NewReader(b.Bytes()), int64(b.Len()))
+       if err != nil {
+               t.Fatalf("NewReader failed: %s", err)
+       }
+       if len(r.File) != 5 {
+               t.Errorf("Archive has unexpected number of files, got %d, want 5", len(r.File))
+       }
+}
index a2c2a2d98e88e7fee95fcbd944528f65f6edd36e..eaa94975ec21a266985199e889b4d461fca5d3bd 100644 (file)
@@ -7,10 +7,13 @@ package ssa
 import (
        "cmd/compile/internal/abi"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/types"
        "cmd/internal/dwarf"
        "cmd/internal/obj"
+       "cmd/internal/src"
        "encoding/hex"
        "fmt"
+       "internal/buildcfg"
        "math/bits"
        "sort"
        "strings"
@@ -335,6 +338,216 @@ func (s *debugState) stateString(state stateAtPC) string {
        return strings.Join(strs, "")
 }
 
+// slotCanonicalizer is a table used to lookup and canonicalize
+// LocalSlot's in a type insensitive way (e.g. taking into account the
+// base name, offset, and width of the slot, but ignoring the slot
+// type).
+type slotCanonicalizer struct {
+       slmap  map[slotKey]SlKeyIdx
+       slkeys []LocalSlot
+}
+
+func newSlotCanonicalizer() *slotCanonicalizer {
+       return &slotCanonicalizer{
+               slmap:  make(map[slotKey]SlKeyIdx),
+               slkeys: []LocalSlot{LocalSlot{N: nil}},
+       }
+}
+
+type SlKeyIdx uint32
+
+const noSlot = SlKeyIdx(0)
+
+// slotKey is a type-insensitive encapsulation of a LocalSlot; it
+// is used to key a map within slotCanonicalizer.
+type slotKey struct {
+       name        *ir.Name
+       offset      int64
+       width       int64
+       splitOf     SlKeyIdx // idx in slkeys slice in slotCanonicalizer
+       splitOffset int64
+}
+
+// lookup looks up a LocalSlot in the slot canonicalizer "sc", returning
+// a canonical index for the slot, and adding it to the table if need
+// be. Return value is the canonical slot index, and a boolean indicating
+// whether the slot was found in the table already (TRUE => found).
+func (sc *slotCanonicalizer) lookup(ls LocalSlot) (SlKeyIdx, bool) {
+       split := noSlot
+       if ls.SplitOf != nil {
+               split, _ = sc.lookup(*ls.SplitOf)
+       }
+       k := slotKey{
+               name: ls.N, offset: ls.Off, width: ls.Type.Width,
+               splitOf: split, splitOffset: ls.SplitOffset,
+       }
+       if idx, ok := sc.slmap[k]; ok {
+               return idx, true
+       }
+       rv := SlKeyIdx(len(sc.slkeys))
+       sc.slkeys = append(sc.slkeys, ls)
+       sc.slmap[k] = rv
+       return rv, false
+}
+
+func (sc *slotCanonicalizer) canonSlot(idx SlKeyIdx) LocalSlot {
+       return sc.slkeys[idx]
+}
+
+// PopulateABIInRegArgOps examines the entry block of the function
+// and looks for incoming parameters that have missing or partial
+// OpArg{Int,Float}Reg values, inserting additional values in
+// cases where they are missing. Example:
+//
+//      func foo(s string, used int, notused int) int {
+//        return len(s) + used
+//      }
+//
+// In the function above, the incoming parameter "used" is fully live,
+// "notused" is not live, and "s" is partially live (only the length
+// field of the string is used). At the point where debug value
+// analysis runs, we might expect to see an entry block with:
+//
+//   b1:
+//     v4 = ArgIntReg <uintptr> {s+8} [0] : BX
+//     v5 = ArgIntReg <int> {used} [0] : CX
+//
+// While this is an accurate picture of the live incoming params,
+// we also want to have debug locations for non-live params (or
+// their non-live pieces), e.g. something like
+//
+//   b1:
+//     v9 = ArgIntReg <*uint8> {s+0} [0] : AX
+//     v4 = ArgIntReg <uintptr> {s+8} [0] : BX
+//     v5 = ArgIntReg <int> {used} [0] : CX
+//     v10 = ArgIntReg <int> {unused} [0] : DI
+//
+// This function examines the live OpArg{Int,Float}Reg values and
+// synthesizes new (dead) values for the non-live params or the
+// non-live pieces of partially live params.
+//
+func PopulateABIInRegArgOps(f *Func) {
+       pri := f.ABISelf.ABIAnalyzeFuncType(f.Type.FuncType())
+
+       // When manufacturing new slots that correspond to splits of
+       // composite parameters, we want to avoid creating a new sub-slot
+       // that differs from some existing sub-slot only by type, since
+       // the debug location analysis will treat that slot as a separate
+       // entity. To achieve this, create a lookup table of existing
+       // slots that is type-insenstitive.
+       sc := newSlotCanonicalizer()
+       for _, sl := range f.Names {
+               sc.lookup(*sl)
+       }
+
+       // Add slot -> value entry to f.NamedValues if not already present.
+       addToNV := func(v *Value, sl LocalSlot) {
+               values, ok := f.NamedValues[sl]
+               if !ok {
+                       // Haven't seen this slot yet.
+                       sla := f.localSlotAddr(sl)
+                       f.Names = append(f.Names, sla)
+               } else {
+                       for _, ev := range values {
+                               if v == ev {
+                                       return
+                               }
+                       }
+               }
+               values = append(values, v)
+               f.NamedValues[sl] = values
+       }
+
+       newValues := []*Value{}
+
+       abiRegIndexToRegister := func(reg abi.RegIndex) int8 {
+               i := f.ABISelf.FloatIndexFor(reg)
+               if i >= 0 { // float PR
+                       return f.Config.floatParamRegs[i]
+               } else {
+                       return f.Config.intParamRegs[reg]
+               }
+       }
+
+       // Helper to construct a new OpArg{Float,Int}Reg op value.
+       var pos src.XPos
+       if len(f.Entry.Values) != 0 {
+               pos = f.Entry.Values[0].Pos
+       }
+       synthesizeOpIntFloatArg := func(n *ir.Name, t *types.Type, reg abi.RegIndex, sl LocalSlot) *Value {
+               aux := &AuxNameOffset{n, sl.Off}
+               op, auxInt := ArgOpAndRegisterFor(reg, f.ABISelf)
+               v := f.newValueNoBlock(op, t, pos)
+               v.AuxInt = auxInt
+               v.Aux = aux
+               v.Args = nil
+               v.Block = f.Entry
+               newValues = append(newValues, v)
+               addToNV(v, sl)
+               f.setHome(v, &f.Config.registers[abiRegIndexToRegister(reg)])
+               return v
+       }
+
+       // Make a pass through the entry block looking for
+       // OpArg{Int,Float}Reg ops. Record the slots they use in a table
+       // ("sc"). We use a type-insensitive lookup for the slot table,
+       // since the type we get from the ABI analyzer won't always match
+       // what the compiler uses when creating OpArg{Int,Float}Reg ops.
+       for _, v := range f.Entry.Values {
+               if v.Op == OpArgIntReg || v.Op == OpArgFloatReg {
+                       aux := v.Aux.(*AuxNameOffset)
+                       sl := LocalSlot{N: aux.Name, Type: v.Type, Off: aux.Offset}
+                       // install slot in lookup table
+                       idx, _ := sc.lookup(sl)
+                       // add to f.NamedValues if not already present
+                       addToNV(v, sc.canonSlot(idx))
+               } else if v.Op.IsCall() {
+                       // if we hit a call, we've gone too far.
+                       break
+               }
+       }
+
+       // Now make a pass through the ABI in-params, looking for params
+       // or pieces of params that we didn't encounter in the loop above.
+       for _, inp := range pri.InParams() {
+               if !isNamedRegParam(inp) {
+                       continue
+               }
+               n := inp.Name.(*ir.Name)
+
+               // Param is spread across one or more registers. Walk through
+               // each piece to see whether we've seen an arg reg op for it.
+               types, offsets := inp.RegisterTypesAndOffsets()
+               for k, t := range types {
+                       // Note: this recipe for creating a LocalSlot is designed
+                       // to be compatible with the one used in expand_calls.go
+                       // as opposed to decompose.go. The expand calls code just
+                       // takes the base name and creates an offset into it,
+                       // without using the SplitOf/SplitOffset fields. The code
+                       // in decompose.go does the opposite -- it creates a
+                       // LocalSlot object with "Off" set to zero, but with
+                       // SplitOf pointing to a parent slot, and SplitOffset
+                       // holding the offset into the parent object.
+                       pieceSlot := LocalSlot{N: n, Type: t, Off: offsets[k]}
+
+                       // Look up this piece to see if we've seen a reg op
+                       // for it. If not, create one.
+                       _, found := sc.lookup(pieceSlot)
+                       if !found {
+                               // This slot doesn't appear in the map, meaning it
+                               // corresponds to an in-param that is not live, or
+                               // a portion of an in-param that is not live/used.
+                               // Add a new dummy OpArg{Int,Float}Reg for it.
+                               synthesizeOpIntFloatArg(n, t, inp.Registers[k],
+                                       pieceSlot)
+                       }
+               }
+       }
+
+       // Insert the new values into the head of the block.
+       f.Entry.Values = append(newValues, f.Entry.Values...)
+}
+
 // BuildFuncDebug returns debug information for f.
 // f must be fully processed, so that each Value is where it will be when
 // machine code is emitted.
@@ -349,6 +562,10 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
        state.stackOffset = stackOffset
        state.ctxt = ctxt
 
+       if buildcfg.Experiment.RegabiArgs {
+               PopulateABIInRegArgOps(f)
+       }
+
        if state.loggingEnabled {
                state.logf("Generating location lists for function %q\n", f.Name)
        }
index c81d5574fe5fee1a9a96d6a57c6f8c5c5b67ab7f..3b90b8769c2f1d8ffe484b0ab40d832aea650175 100644 (file)
@@ -1882,6 +1882,10 @@ func (s *regAllocState) placeSpills() {
                phiRegs[b.ID] = m
        }
 
+       mustBeFirst := func(op Op) bool {
+               return op.isLoweredGetClosurePtr() || op == OpPhi || op == OpArgIntReg || op == OpArgFloatReg
+       }
+
        // Start maps block IDs to the list of spills
        // that go at the start of the block (but after any phis).
        start := map[ID][]*Value{}
@@ -1971,7 +1975,7 @@ func (s *regAllocState) placeSpills() {
                // Put the spill in the best block we found.
                spill.Block = best
                spill.AddArg(bestArg)
-               if best == v.Block && v.Op != OpPhi {
+               if best == v.Block && !mustBeFirst(v.Op) {
                        // Place immediately after v.
                        after[v.ID] = append(after[v.ID], spill)
                } else {
@@ -1983,15 +1987,15 @@ func (s *regAllocState) placeSpills() {
        // Insert spill instructions into the block schedules.
        var oldSched []*Value
        for _, b := range s.visitOrder {
-               nphi := 0
+               nfirst := 0
                for _, v := range b.Values {
-                       if v.Op != OpPhi {
+                       if !mustBeFirst(v.Op) {
                                break
                        }
-                       nphi++
+                       nfirst++
                }
-               oldSched = append(oldSched[:0], b.Values[nphi:]...)
-               b.Values = b.Values[:nphi]
+               oldSched = append(oldSched[:0], b.Values[nfirst:]...)
+               b.Values = b.Values[:nfirst]
                b.Values = append(b.Values, start[b.ID]...)
                for _, v := range oldSched {
                        b.Values = append(b.Values, v)
index bad2b7f16efbf9266ce178a6be3122a5805cab7a..ab61017c4eb5598acfd00af405267027a5de5f2f 100644 (file)
 //
 // Usage:
 //
-//     go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]
+//     go doc [doc flags] [package|[package.]symbol[.methodOrField]]
 //
 // Doc prints the documentation comments associated with the item identified by its
 // arguments (a package, const, func, type, var, method, or struct field)
index 67f76e22563b6e84d21b7622b55675d03af60db2..8580a5dc4d2482a7e2f88640abe9a76a245adb18 100644 (file)
@@ -13,7 +13,7 @@ import (
 
 var CmdDoc = &base.Command{
        Run:         runDoc,
-       UsageLine:   "go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]",
+       UsageLine:   "go doc [doc flags] [package|[package.]symbol[.methodOrField]]",
        CustomFlags: true,
        Short:       "show documentation for package or symbol",
        Long: `
index 42b06dbc95c44bf04f7b42a4e13def2ec0d1f674..0e5af852376e76c5363d595d15c55f18d4acd8f6 100644 (file)
@@ -138,14 +138,14 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
        sem := make(chan token, runtime.GOMAXPROCS(0))
        infos, infosErr := modload.ListModules(ctx, args, 0)
        if !haveExplicitArgs {
-               // 'go mod download' is sometimes run without arguments to pre-populate
-               // the module cache. It may fetch modules that aren't needed to build
-               // packages in the main mdoule. This is usually not intended, so don't save
-               // sums for downloaded modules (golang.org/issue/45332).
-               // TODO(golang.org/issue/45551): For now, save sums needed to load the
-               // build list (same as 1.15 behavior). In the future, report an error if
-               // go.mod or go.sum need to be updated after loading the build list.
-               modload.WriteGoMod(ctx)
+               // 'go mod download' is sometimes run without arguments to pre-populate the
+               // module cache. It may fetch modules that aren't needed to build packages
+               // in the main mdoule. This is usually not intended, so don't save sums for
+               // downloaded modules (golang.org/issue/45332).
+               // TODO(golang.org/issue/45551): For now, in ListModules, save sums needed
+               // to load the build list (same as 1.15 behavior). In the future, report an
+               // error if go.mod or go.sum need to be updated after loading the build
+               // list.
                modload.DisallowWriteGoMod()
        }
 
index 563f1a988f08ee3f005b0b23f01d08c47a7060ed..8eee723f89b38d0310dd66be33aee0a7645cd240 100644 (file)
@@ -38,6 +38,7 @@ import (
        "cmd/go/internal/base"
        "cmd/go/internal/imports"
        "cmd/go/internal/load"
+       "cmd/go/internal/modfetch"
        "cmd/go/internal/modload"
        "cmd/go/internal/par"
        "cmd/go/internal/search"
@@ -1466,6 +1467,8 @@ func (r *resolver) chooseArbitrarily(cs pathSet) (isPackage bool, m module.Versi
 // checkPackageProblems reloads packages for the given patterns and reports
 // missing and ambiguous package errors. It also reports retractions and
 // deprecations for resolved modules and modules needed to build named packages.
+// It also adds a sum for each updated module in the build list if we had one
+// before and didn't get one while loading packages.
 //
 // We skip missing-package errors earlier in the process, since we want to
 // resolve pathSets ourselves, but at that point, we don't have enough context
@@ -1593,9 +1596,52 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin
                })
        }
 
+       // Load sums for updated modules that had sums before. When we update a
+       // module, we may update another module in the build list that provides a
+       // package in 'all' that wasn't loaded as part of this 'go get' command.
+       // If we don't add a sum for that module, builds may fail later.
+       // Note that an incidentally updated package could still import packages
+       // from unknown modules or from modules in the build list that we didn't
+       // need previously. We can't handle that case without loading 'all'.
+       sumErrs := make([]error, len(r.buildList))
+       for i := range r.buildList {
+               i := i
+               m := r.buildList[i]
+               mActual := m
+               if mRepl := modload.Replacement(m); mRepl.Path != "" {
+                       mActual = mRepl
+               }
+               old := module.Version{Path: m.Path, Version: r.initialVersion[m.Path]}
+               if old.Version == "" {
+                       continue
+               }
+               oldActual := old
+               if oldRepl := modload.Replacement(old); oldRepl.Path != "" {
+                       oldActual = oldRepl
+               }
+               if mActual == oldActual || mActual.Version == "" || !modfetch.HaveSum(oldActual) {
+                       continue
+               }
+               r.work.Add(func() {
+                       if _, err := modfetch.DownloadZip(ctx, mActual); err != nil {
+                               verb := "upgraded"
+                               if semver.Compare(m.Version, old.Version) < 0 {
+                                       verb = "downgraded"
+                               }
+                               replaced := ""
+                               if mActual != m {
+                                       replaced = fmt.Sprintf(" (replaced by %s)", mActual)
+                               }
+                               err = fmt.Errorf("%s %s %s => %s%s: error finding sum for %s: %v", verb, m.Path, old.Version, m.Version, replaced, mActual, err)
+                               sumErrs[i] = err
+                       }
+               })
+       }
+
        <-r.work.Idle()
 
-       // Report deprecations, then retractions.
+       // Report deprecations, then retractions, then errors fetching sums.
+       // Only errors fetching sums are hard errors.
        for _, mm := range deprecations {
                if mm.message != "" {
                        fmt.Fprintf(os.Stderr, "go: module %s is deprecated: %s\n", mm.m.Path, mm.message)
@@ -1615,6 +1661,12 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin
        if retractPath != "" {
                fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest\n", retractPath)
        }
+       for _, err := range sumErrs {
+               if err != nil {
+                       base.Errorf("go: %v", err)
+               }
+       }
+       base.ExitIfErrors()
 }
 
 // reportChanges logs version changes to os.Stderr.
index 86c0db3fe4f097d1a6a601b142812f4dab8cd924..ea404b9f78f496ba5577e0809d6d186d35d66279 100644 (file)
@@ -1122,12 +1122,11 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums
                }
        }
 
-       if rs.depth == lazy && rs.graph.Load() == nil {
-               // The main module is lazy and we haven't needed to load the module graph so
-               // far. Don't incur the cost of loading it now â€” since we haven't loaded the
-               // graph, we probably don't have any checksums to contribute to the distant
-               // parts of the graph anyway. Instead, just request sums for the roots that
-               // we know about.
+       if rs.graph.Load() == nil {
+               // The module graph was not loaded, possibly because the main module is lazy
+               // or possibly because we haven't needed to load the graph yet.
+               // Save sums for the root modules (or their replacements), but don't
+               // incur the cost of loading the graph just to find and retain the sums.
                for _, m := range rs.rootModules {
                        r := resolveReplacement(m)
                        keep[modkey(r)] = true
diff --git a/src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt b/src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt
deleted file mode 100644 (file)
index 38a151e..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# Tests Issue #12690
-
-[gccgo] skip 'gccgo does not have GOROOT'
-
-! stale runtime
-! stale os
-! stale io
-
-env GOROOT=$GOROOT'/'
-
-! stale runtime
-! stale os
-! stale io
\ No newline at end of file
diff --git a/src/cmd/go/testdata/script/cgo_stale.txt b/src/cmd/go/testdata/script/cgo_stale.txt
new file mode 100644 (file)
index 0000000..9e46855
--- /dev/null
@@ -0,0 +1,39 @@
+# golang.org/issue/46347: a stale runtime/cgo should only force a single rebuild
+
+[!cgo] skip
+[short] skip
+
+
+# If we set a unique CGO_CFLAGS, the installed copy of runtime/cgo
+# should be reported as stale.
+
+env CGO_CFLAGS=-DTestScript_cgo_stale=true
+stale runtime/cgo
+
+
+# If we then build a package that uses cgo, runtime/cgo should be rebuilt and
+# cached with the new flag, but not installed to GOROOT (and thus still stale).
+
+env GOCACHE=$WORK/cache  # Use a fresh cache to avoid interference between runs.
+
+go build -x .
+stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo'
+stale runtime/cgo
+
+
+# After runtime/cgo has been rebuilt and cached, it should not be rebuilt again
+# even though it is still reported as stale.
+
+go build -x .
+! stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo'
+stale runtime/cgo
+
+
+-- go.mod --
+module example.com/m
+
+go 1.17
+-- m.go --
+package m
+
+import "C"
diff --git a/src/cmd/go/testdata/script/list_std_stale.txt b/src/cmd/go/testdata/script/list_std_stale.txt
deleted file mode 100644 (file)
index e5c1f33..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-# https://golang.org/issue/44725: packages in std should not be reported as stale,
-# regardless of whether they are listed from within or outside GOROOT/src.
-
-# Control case: net should not be stale at the start of the test,
-# and should depend on vendor/golang.org/… instead of golang.org/….
-
-! stale net
-
-go list -deps net
-stdout '^vendor/golang.org/x/net'
-! stdout '^golang.org/x/net'
-
-# Net should also not be stale when viewed from within GOROOT/src,
-# and should still report the same package dependencies.
-
-cd $GOROOT/src
-! stale net
-
-go list -deps net
-stdout '^vendor/golang.org/x/net'
-! stdout '^golang.org/x/net'
-
-
-# However, 'go mod' and 'go get' subcommands should report the original module
-# dependencies, not the vendored packages.
-
-[!net] stop
-
-env GOPROXY=
-go mod why -m golang.org/x/net
-stdout '^# golang.org/x/net\nnet\ngolang.org/x/net'
diff --git a/src/cmd/go/testdata/script/list_std_vendor.txt b/src/cmd/go/testdata/script/list_std_vendor.txt
new file mode 100644 (file)
index 0000000..8f27cc1
--- /dev/null
@@ -0,0 +1,32 @@
+# https://golang.org/issue/44725: packages in std should have the same
+# dependencies regardless of whether they are listed from within or outside
+# GOROOT/src.
+
+# Control case: net, viewed from outside the 'std' module,
+# should depend on vendor/golang.org/… instead of golang.org/….
+
+go list -deps net
+stdout '^vendor/golang.org/x/net'
+! stdout '^golang.org/x/net'
+cp stdout $WORK/net-deps.txt
+
+
+# It should still report the same package dependencies when viewed from
+# within GOROOT/src.
+
+cd $GOROOT/src
+
+go list -deps net
+stdout '^vendor/golang.org/x/net'
+! stdout '^golang.org/x/net'
+cmp stdout $WORK/net-deps.txt
+
+
+# However, 'go mod' and 'go get' subcommands should report the original module
+# dependencies, not the vendored packages.
+
+[!net] stop
+
+env GOPROXY=
+go mod why -m golang.org/x/net
+stdout '^# golang.org/x/net\nnet\ngolang.org/x/net'
index ad640b45de11512668468a17c7921b8e289b05f6..c2b72b2a02cab8f681872c637d1d9990c9131db5 100644 (file)
@@ -167,5 +167,4 @@ require (
 -- update/go.sum.update --
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
-rsc.io/sampler v1.2.1/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
diff --git a/src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt b/src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt
new file mode 100644 (file)
index 0000000..0093c0e
--- /dev/null
@@ -0,0 +1,120 @@
+# Check that 'go get' adds sums for updated modules if we had sums before,
+# even if we didn't load packages from them.
+# Verifies #44129.
+
+env fmt='{{.ImportPath}}: {{if .Error}}{{.Error.Err}}{{else}}ok{{end}}'
+
+# Control case: before upgrading, we have the sums we need.
+# go list -deps -e -f $fmt .
+# stdout '^rsc.io/quote: ok$'
+# ! stdout rsc.io/sampler  # not imported by quote in this version
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+go mod tidy
+cmp go.mod.orig go.mod
+cmp go.sum.orig go.sum
+
+
+# Upgrade a module. This also upgrades rsc.io/quote, and though we didn't load
+# a package from it, we had the sum for its old version, so we need the
+# sum for the new version, too.
+go get -d example.com/upgrade@v0.0.2
+grep '^rsc.io/quote v1.5.2 ' go.sum
+
+# The upgrade still breaks the build because the new version of quote imports
+# rsc.io/sampler, and we don't have its zip sum.
+go list -deps -e -f $fmt
+stdout 'rsc.io/quote: ok'
+stdout 'rsc.io/sampler: missing go.sum entry for module providing package rsc.io/sampler'
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+
+
+# Replace the old version with a directory before upgrading.
+# We didn't need a sum for it before (even though we had one), so we won't
+# fetch a new sum.
+go mod edit -replace rsc.io/quote@v1.0.0=./dummy
+go get -d example.com/upgrade@v0.0.2
+! grep '^rsc.io/quote v1.5.2 ' go.sum
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+
+
+# Replace the new version with a directory before upgrading.
+# We can't get a sum for a directory.
+go mod edit -replace rsc.io/quote@v1.5.2=./dummy
+go get -d example.com/upgrade@v0.0.2
+! grep '^rsc.io/quote v1.5.2 ' go.sum
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+
+
+# Replace the new version with a different version.
+# We should get a sum for that version.
+go mod edit -replace rsc.io/quote@v1.5.2=rsc.io/quote@v1.5.1
+go get -d example.com/upgrade@v0.0.2
+! grep '^rsc.io/quote v1.5.2 ' go.sum
+grep '^rsc.io/quote v1.5.1 ' go.sum
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+
+
+# Delete the new version's zip (but not mod) from the cache and go offline.
+# 'go get' should fail when fetching the zip.
+rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
+env GOPROXY=off
+! go get -d example.com/upgrade@v0.0.2
+stderr '^go: upgraded rsc.io/quote v1.0.0 => v1.5.2: error finding sum for rsc.io/quote@v1.5.2: module lookup disabled by GOPROXY=off$'
+
+-- go.mod.orig --
+module m
+
+go 1.16
+
+require (
+       example.com/upgrade v0.0.1
+       rsc.io/quote v1.0.0
+)
+
+replace (
+       example.com/upgrade v0.0.1 => ./upgrade1
+       example.com/upgrade v0.0.2 => ./upgrade2
+)
+-- go.sum.orig --
+rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw=
+rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA=
+-- go.sum.want --
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw=
+rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA=
+rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0=
+rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+-- use.go --
+package use
+
+import (
+       _ "example.com/upgrade"
+       _ "rsc.io/quote"
+)
+-- upgrade1/go.mod --
+module example.com/upgrade
+
+go 1.16
+-- upgrade1/upgrade.go --
+package upgrade
+-- upgrade2/go.mod --
+module example.com/upgrade
+
+go 1.16
+
+require rsc.io/quote v1.5.2 // indirect
+-- upgrade2/upgrade.go --
+package upgrade
+-- dummy/go.mod --
+module rsc.io/quote
+
+go 1.16
+-- dummy/quote.go --
+package quote
+
index 3f4eb90e3f66e72b48cc52106ea8a9868706e8c9..e1fe4f2acea96f161198dec4f45558d341749f6f 100644 (file)
@@ -2,8 +2,6 @@
 
 [!race] skip
 
-[!darwin] ! stale cmd/cgo  # The darwin builders are spuriously stale; see #33598.
-
 env GOBIN=$WORK/bin
 go install m/mtime m/sametime
 
index 4f26da6d26bbd52721824e9b7528f8af75392907..bb86467942b9fd240c3f0579818564672d607e1f 100644 (file)
@@ -3,6 +3,12 @@
 # Build our simple toolexec program.
 go build ./cmd/mytool
 
+# Use an ephemeral build cache so that our toolexec output is not cached
+# for any stale standard-library dependencies.
+#
+# TODO(#27628): This should not be necessary.
+env GOCACHE=$WORK/gocache
+
 # Build the main package with our toolexec program. For each action, it will
 # print the tool's name and the TOOLEXEC_IMPORTPATH value. We expect to compile
 # each package once, and link the main package once.
index 0419613cbe2e78bb06dc8d87e3c25f79b011ea56..3ca59bd47f025cf1eac24eac43fddec1700c2348 100644 (file)
@@ -19,6 +19,36 @@ import (
        "testing"
 )
 
+// TestMain allows this test binary to run as a -toolexec wrapper for the 'go'
+// command. If LINK_TEST_TOOLEXEC is set, TestMain runs the binary as if it were
+// cmd/link, and otherwise runs the requested tool as a subprocess.
+//
+// This allows the test to verify the behavior of the current contents of the
+// cmd/link package even if the installed cmd/link binary is stale.
+func TestMain(m *testing.M) {
+       if os.Getenv("LINK_TEST_TOOLEXEC") == "" {
+               // Not running as a -toolexec wrapper. Just run the tests.
+               os.Exit(m.Run())
+       }
+
+       if strings.TrimSuffix(filepath.Base(os.Args[1]), ".exe") == "link" {
+               // Running as a -toolexec linker, and the tool is cmd/link.
+               // Substitute this test binary for the linker.
+               os.Args = os.Args[1:]
+               main()
+               os.Exit(0)
+       }
+
+       cmd := exec.Command(os.Args[1], os.Args[2:]...)
+       cmd.Stdin = os.Stdin
+       cmd.Stdout = os.Stdout
+       cmd.Stderr = os.Stderr
+       if err := cmd.Run(); err != nil {
+               os.Exit(1)
+       }
+       os.Exit(0)
+}
+
 func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) {
        testenv.MustHaveCGO(t)
        testenv.MustHaveGoBuild(t)
@@ -29,17 +59,6 @@ func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string)
 
        t.Parallel()
 
-       out, err := exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "cmd/link").CombinedOutput()
-       if err != nil {
-               t.Fatalf("go list: %v\n%s", err, out)
-       }
-       if string(out) != "false\n" {
-               if strings.HasPrefix(testenv.Builder(), "darwin-") {
-                       t.Skipf("cmd/link is spuriously stale on Darwin builders - see #33598")
-               }
-               t.Fatalf("cmd/link is stale - run go install cmd/link")
-       }
-
        for _, prog := range []string{"testprog", "testprogcgo"} {
                prog := prog
                expectDWARF := expectDWARF
@@ -48,11 +67,11 @@ func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string)
                        if extld == "" {
                                extld = "gcc"
                        }
+                       var err error
                        expectDWARF, err = cmddwarf.IsDWARFEnabledOnAIXLd(extld)
                        if err != nil {
                                t.Fatal(err)
                        }
-
                }
 
                t.Run(prog, func(t *testing.T) {
@@ -62,15 +81,14 @@ func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string)
 
                        exe := filepath.Join(tmpDir, prog+".exe")
                        dir := "../../runtime/testdata/" + prog
-                       cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
+                       cmd := exec.Command(testenv.GoToolPath(t), "build", "-toolexec", os.Args[0], "-o", exe)
                        if buildmode != "" {
                                cmd.Args = append(cmd.Args, "-buildmode", buildmode)
                        }
                        cmd.Args = append(cmd.Args, dir)
-                       if env != nil {
-                               cmd.Env = append(os.Environ(), env...)
-                               cmd.Env = append(cmd.Env, "CGO_CFLAGS=") // ensure CGO_CFLAGS does not contain any flags. Issue #35459
-                       }
+                       cmd.Env = append(os.Environ(), env...)
+                       cmd.Env = append(cmd.Env, "CGO_CFLAGS=") // ensure CGO_CFLAGS does not contain any flags. Issue #35459
+                       cmd.Env = append(cmd.Env, "LINK_TEST_TOOLEXEC=1")
                        out, err := cmd.CombinedOutput()
                        if err != nil {
                                t.Fatalf("go build -o %v %v: %v\n%s", exe, dir, err, out)
index 223df63d9df7af62f43e86a0ef83fb358b8e1495..70fbb9dc4e24cf2d47c78c89b072684625735784 100644 (file)
@@ -1550,7 +1550,7 @@ func (ctxt *Link) dodata(symGroupType []sym.SymKind) {
 
        if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
                // These symbols must have the same alignment as their section.
-               // Otherwize, ld might change the layout of Go sections.
+               // Otherwise, ld might change the layout of Go sections.
                ldr.SetSymAlign(ldr.Lookup("runtime.data", 0), state.dataMaxAlign[sym.SDATA])
                ldr.SetSymAlign(ldr.Lookup("runtime.bss", 0), state.dataMaxAlign[sym.SBSS])
        }
index 8805ff1f02cacbb4cc4db2f59af85a5ab51227a3..4d6bc76aca82a588ace4b2ca8f48c010b195244b 100644 (file)
@@ -698,7 +698,7 @@ func TestTrampolineCgo(t *testing.T) {
        if err != nil {
                t.Errorf("executable failed to run: %v\n%s", err, out)
        }
-       if string(out) != "hello\n" {
+       if string(out) != "hello\n" && string(out) != "hello\r\n" {
                t.Errorf("unexpected output:\n%s", out)
        }
 
@@ -717,7 +717,7 @@ func TestTrampolineCgo(t *testing.T) {
        if err != nil {
                t.Errorf("executable failed to run: %v\n%s", err, out)
        }
-       if string(out) != "hello\n" {
+       if string(out) != "hello\n" && string(out) != "hello\r\n" {
                t.Errorf("unexpected output:\n%s", out)
        }
 }
index ce74e0539c9a64ba66f27e7efe896f2b8f675967..3d355943ec7fae1545ea804c20a9e63b398dcf47 100644 (file)
@@ -52,7 +52,7 @@ func (curve p521Curve) IsOnCurve(x, y *big.Int) bool {
        return x3.Equal(y2) == 1
 }
 
-type p512Point struct {
+type p521Point struct {
        x, y, z *fiat.P521Element
 }
 
@@ -67,7 +67,7 @@ func fiatP521ToBigInt(x *fiat.P521Element) *big.Int {
 // affineFromJacobian brings a point in Jacobian coordinates back to affine
 // coordinates, with (0, 0) representing infinity by convention. It also goes
 // back to big.Int values to match the exposed API.
-func (curve p521Curve) affineFromJacobian(p *p512Point) (x, y *big.Int) {
+func (curve p521Curve) affineFromJacobian(p *p521Point) (x, y *big.Int) {
        if p.z.IsZero() == 1 {
                return new(big.Int), new(big.Int)
        }
@@ -99,17 +99,17 @@ func bigIntToFiatP521(x *big.Int) *fiat.P521Element {
 // jacobianFromAffine converts (x, y) affine coordinates into (x, y, z) Jacobian
 // coordinates. It also converts from big.Int to fiat, which is necessarily a
 // messy and variable-time operation, which we can't avoid due to the exposed API.
-func (curve p521Curve) jacobianFromAffine(x, y *big.Int) *p512Point {
+func (curve p521Curve) jacobianFromAffine(x, y *big.Int) *p521Point {
        // (0, 0) is by convention the point at infinity, which can't be represented
        // in affine coordinates, but is (0, 0, 0) in Jacobian.
        if x.Sign() == 0 && y.Sign() == 0 {
-               return &p512Point{
+               return &p521Point{
                        x: new(fiat.P521Element),
                        y: new(fiat.P521Element),
                        z: new(fiat.P521Element),
                }
        }
-       return &p512Point{
+       return &p521Point{
                x: bigIntToFiatP521(x),
                y: bigIntToFiatP521(y),
                z: new(fiat.P521Element).One(),
@@ -123,7 +123,7 @@ func (curve p521Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
 }
 
 // addJacobian sets q = p1 + p2, and returns q. The points may overlap.
-func (q *p512Point) addJacobian(p1, p2 *p512Point) *p512Point {
+func (q *p521Point) addJacobian(p1, p2 *p521Point) *p521Point {
        // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
        z1IsZero := p1.z.IsZero()
        z2IsZero := p2.z.IsZero()
@@ -189,7 +189,7 @@ func (curve p521Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
 }
 
 // doubleJacobian sets q = p + p, and returns q. The points may overlap.
-func (q *p512Point) doubleJacobian(p *p512Point) *p512Point {
+func (q *p521Point) doubleJacobian(p *p521Point) *p521Point {
        // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
        delta := new(fiat.P521Element).Square(p.z)
        gamma := new(fiat.P521Element).Square(p.y)
@@ -230,11 +230,11 @@ func (q *p512Point) doubleJacobian(p *p512Point) *p512Point {
 
 func (curve p521Curve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
        B := curve.jacobianFromAffine(Bx, By)
-       p, t := &p512Point{
+       p, t := &p521Point{
                x: new(fiat.P521Element),
                y: new(fiat.P521Element),
                z: new(fiat.P521Element),
-       }, &p512Point{
+       }, &p521Point{
                x: new(fiat.P521Element),
                y: new(fiat.P521Element),
                z: new(fiat.P521Element),
index c87529ec77dda9399b803cfe632b7b9fc2f90904..337c87fd797351c344bf3e4b2ea01c20b3235c2e 100644 (file)
@@ -259,7 +259,7 @@ func (f *FieldList) End() token.Pos {
        return token.NoPos
 }
 
-// NumFields returns the number of (type) parameters or struct fields represented by a FieldList.
+// NumFields returns the number of parameters or struct fields represented by a FieldList.
 func (f *FieldList) NumFields() int {
        n := 0
        if f != nil {
@@ -973,10 +973,6 @@ type (
        }
 )
 
-func (f *FuncDecl) IsMethod() bool {
-       return f.Recv.NumFields() != 0
-}
-
 // Pos and End implementations for declaration nodes.
 
 func (d *BadDecl) Pos() token.Pos  { return d.From }
index ed62a785d6c9c12ba9021348c7dc150b821c92f2..8c0d9d22bf26aa671f6bf65c7676dc2bf806a78a 100644 (file)
@@ -101,12 +101,12 @@ type ImporterFrom interface {
 // A Config specifies the configuration for type checking.
 // The zero value for Config is a ready-to-use default configuration.
 type Config struct {
-       // GoVersion describes the accepted Go language version. The string
+       // goVersion describes the accepted Go language version. The string
        // must follow the format "go%d.%d" (e.g. "go1.12") or it must be
        // empty; an empty string indicates the latest language version.
        // If the format is invalid, invoking the type checker will cause a
        // panic.
-       GoVersion string
+       goVersion string
 
        // If IgnoreFuncBodies is set, function bodies are not
        // type-checked.
index 25ea4906be35f52f38909b1d458c5416be8c2b0d..a923c3c612124f21f6baa59cec4967ee5084a271 100644 (file)
@@ -179,9 +179,9 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
                info = new(Info)
        }
 
-       version, err := parseGoVersion(conf.GoVersion)
+       version, err := parseGoVersion(conf.goVersion)
        if err != nil {
-               panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err))
+               panic(fmt.Sprintf("invalid Go version %q (%v)", conf.goVersion, err))
        }
 
        return &Checker{
index c5dc93eade6b7b010558350221313a86d56e7fbe..6c3b630a1b6ef54b075caec94d1595185534ec1d 100644 (file)
@@ -240,7 +240,7 @@ func checkFiles(t *testing.T, sizes Sizes, goVersion string, filenames []string,
        // typecheck and collect typechecker errors
        var conf Config
        conf.Sizes = sizes
-       conf.GoVersion = goVersion
+       SetGoVersion(&conf, goVersion)
 
        // special case for importC.src
        if len(filenames) == 1 {
@@ -330,6 +330,14 @@ func TestIndexRepresentability(t *testing.T) {
        checkFiles(t, &StdSizes{4, 4}, "", []string{"index.go"}, [][]byte{[]byte(src)}, false)
 }
 
+func TestIssue46453(t *testing.T) {
+       if typeparams.Enabled {
+               t.Skip("type params are enabled")
+       }
+       const src = "package p\ntype _ comparable // ERROR \"undeclared name: comparable\""
+       checkFiles(t, nil, "", []string{"issue46453.go"}, [][]byte{[]byte(src)}, false)
+}
+
 func TestCheck(t *testing.T)     { DefPredeclaredTestFuncs(); testDir(t, "check") }
 func TestExamples(t *testing.T)  { testDir(t, "examples") }
 func TestFixedbugs(t *testing.T) { testDir(t, "fixedbugs") }
index 5f38a346cee82600da867b1f968026f0bf196fad..9211febc6da1620a43e9867af2f37c149a6f0753 100644 (file)
@@ -577,15 +577,37 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
 // n0.check != nil, the cycle is reported.
 func (n0 *Named) under() Type {
        u := n0.underlying
-       if u == nil {
-               return Typ[Invalid]
+
+       if u == Typ[Invalid] {
+               return u
        }
 
        // If the underlying type of a defined type is not a defined
-       // type, then that is the desired underlying type.
+       // (incl. instance) type, then that is the desired underlying
+       // type.
+       switch u.(type) {
+       case nil:
+               return Typ[Invalid]
+       default:
+               // common case
+               return u
+       case *Named, *instance:
+               // handled below
+       }
+
+       if n0.check == nil {
+               panic("internal error: Named.check == nil but type is incomplete")
+       }
+
+       // Invariant: after this point n0 as well as any named types in its
+       // underlying chain should be set up when this function exits.
+       check := n0.check
+
+       // If we can't expand u at this point, it is invalid.
        n := asNamed(u)
        if n == nil {
-               return u // common case
+               n0.underlying = Typ[Invalid]
+               return n0.underlying
        }
 
        // Otherwise, follow the forward chain.
@@ -597,7 +619,16 @@ func (n0 *Named) under() Type {
                        u = Typ[Invalid]
                        break
                }
-               n1 := asNamed(u)
+               var n1 *Named
+               switch u1 := u.(type) {
+               case *Named:
+                       n1 = u1
+               case *instance:
+                       n1, _ = u1.expand().(*Named)
+                       if n1 == nil {
+                               u = Typ[Invalid]
+                       }
+               }
                if n1 == nil {
                        break // end of chain
                }
@@ -608,11 +639,7 @@ func (n0 *Named) under() Type {
 
                if i, ok := seen[n]; ok {
                        // cycle
-                       // TODO(rFindley) revert this to a method on Checker. Having a possibly
-                       // nil Checker on Named and TypeParam is too subtle.
-                       if n0.check != nil {
-                               n0.check.cycleError(path[i:])
-                       }
+                       check.cycleError(path[i:])
                        u = Typ[Invalid]
                        break
                }
@@ -622,8 +649,8 @@ func (n0 *Named) under() Type {
                // We should never have to update the underlying type of an imported type;
                // those underlying types should have been resolved during the import.
                // Also, doing so would lead to a race condition (was issue #31749).
-               // Do this check always, not just in debug more (it's cheap).
-               if n0.check != nil && n.obj.pkg != n0.check.pkg {
+               // Do this check always, not just in debug mode (it's cheap).
+               if n.obj.pkg != check.pkg {
                        panic("internal error: imported type with unresolved underlying type")
                }
                n.underlying = u
@@ -665,7 +692,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
        } else {
                // defined type declaration
 
-               named := &Named{check: check, obj: obj}
+               named := check.newNamed(obj, nil, nil)
                def.setUnderlying(named)
                obj.typ = named // make sure recursive type declarations terminate
 
index f67fc65cd18d69c945df5e781f9c32785e265088..114647a2fffecb937bd785c3d85e3467626499a4 100644 (file)
@@ -383,7 +383,7 @@ func (check *Checker) collectObjects() {
                                info := &declInfo{file: fileScope, fdecl: d.decl}
                                name := d.decl.Name.Name
                                obj := NewFunc(d.decl.Name.Pos(), pkg, name, nil)
-                               if !d.decl.IsMethod() {
+                               if d.decl.Recv.NumFields() == 0 {
                                        // regular function
                                        if d.decl.Recv != nil {
                                                check.error(d.decl.Recv, _BadRecv, "method is missing receiver")
index 5970ab38c712dacd6df3b22e770a14ed5e0c48b4..727ec173eac81a4077be56e5f1a1affe9372e88b 100644 (file)
@@ -135,6 +135,9 @@ func (s sanitizer) typ(typ Type) Type {
                }
 
        case *Named:
+               if debug && t.check != nil {
+                       panic("internal error: Named.check != nil")
+               }
                if orig := s.typ(t.orig); orig != t.orig {
                        t.orig = orig
                }
index 3dea8dcf1ed731944dcd10d983e114e83d6ff31b..503d0a6f445afc8e41d45251c8c8fdcbc0d8dc71 100644 (file)
@@ -134,7 +134,8 @@ func testTestDir(t *testing.T, path string, ignore ...string) {
                // parse and type-check file
                file, err := parser.ParseFile(fset, filename, nil, 0)
                if err == nil {
-                       conf := Config{GoVersion: goVersion, Importer: stdLibImporter}
+                       conf := Config{Importer: stdLibImporter}
+                       SetGoVersion(&conf, goVersion)
                        _, err = conf.Check(filename, fset, []*ast.File{file}, nil)
                }
 
index 3303cfc077424f64fc68e6809810780a461d809a..2660ce4408c1b640f67bf517ca72d3819055907e 100644 (file)
@@ -644,7 +644,7 @@ func (c *Chan) Elem() Type { return c.elem }
 
 // A Named represents a named (defined) type.
 type Named struct {
-       check      *Checker    // for Named.under implementation
+       check      *Checker    // for Named.under implementation; nilled once under has been called
        info       typeInfo    // for cycle detection
        obj        *TypeName   // corresponding declared object
        orig       Type        // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
@@ -661,11 +661,7 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
        if _, ok := underlying.(*Named); ok {
                panic("types.NewNamed: underlying type must not be *Named")
        }
-       typ := &Named{obj: obj, orig: underlying, underlying: underlying, methods: methods}
-       if obj.typ == nil {
-               obj.typ = typ
-       }
-       return typ
+       return (*Checker)(nil).newNamed(obj, underlying, methods)
 }
 
 func (check *Checker) newNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
@@ -673,6 +669,23 @@ func (check *Checker) newNamed(obj *TypeName, underlying Type, methods []*Func)
        if obj.typ == nil {
                obj.typ = typ
        }
+       // Ensure that typ is always expanded, at which point the check field can be
+       // nilled out.
+       //
+       // Note that currently we cannot nil out check inside typ.under(), because
+       // it's possible that typ is expanded multiple times.
+       //
+       // TODO(rFindley): clean this up so that under is the only function mutating
+       //                 named types.
+       if check != nil {
+               check.later(func() {
+                       switch typ.under().(type) {
+                       case *Named, *instance:
+                               panic("internal error: unexpanded underlying type")
+                       }
+                       typ.check = nil
+               })
+       }
        return typ
 }
 
index fd9462c4a27a3e856b6b0a727cb080773f3698c2..25cd9966282861ebf71827819813f0e9b44908d0 100644 (file)
@@ -11,3 +11,9 @@ import "sync/atomic"
 // for tests where we may want to have a consistent
 // numbering for each individual test case.
 func ResetId() { atomic.StoreUint32(&lastId, 0) }
+
+// SetGoVersion sets the unexported goVersion field on config, so that tests
+// which assert on behavior for older Go versions can set it.
+func SetGoVersion(config *Config, goVersion string) {
+       config.goVersion = goVersion
+}
index 7c211fa6f7e4add4026f29dc454f7d2f72331f4d..d7feb2c609efa93829bc90bd9176d1d9a423bf94 100644 (file)
@@ -8,6 +8,7 @@ package types
 
 import (
        "go/constant"
+       "go/internal/typeparams"
        "go/token"
        "strings"
 )
@@ -237,7 +238,9 @@ func init() {
        defPredeclaredConsts()
        defPredeclaredNil()
        defPredeclaredFuncs()
-       defPredeclaredComparable()
+       if typeparams.Enabled {
+               defPredeclaredComparable()
+       }
 
        universeIota = Universe.Lookup("iota").(*Const)
        universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic)
index e1947936d498e20c09316cdd27b98fce64362fc0..8f55c195d4bf26e494cd98fc5e4e71c6fe9dd4e8 100644 (file)
@@ -267,20 +267,6 @@ func divWW(x1, x0, y, m Word) (q, r Word) {
        return Word(qq), Word(r0 >> s)
 }
 
-func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) {
-       r = xn
-       if len(x) == 1 {
-               qq, rr := bits.Div(uint(r), uint(x[0]), uint(y))
-               z[0] = Word(qq)
-               return Word(rr)
-       }
-       rec := reciprocalWord(y)
-       for i := len(z) - 1; i >= 0; i-- {
-               z[i], r = divWW(r, x[i], y, rec)
-       }
-       return r
-}
-
 // reciprocalWord return the reciprocal of the divisor. rec = floor(( _B^2 - 1 ) / u - _B). u = d1 << nlz(d1).
 func reciprocalWord(d1 Word) Word {
        u := uint(d1 << nlz(d1))
index bbd6c8850b604b365011144e9ab8e6744ee27354..140c619c8ca7113ff2986d472d31dd202d44bc07 100644 (file)
@@ -631,48 +631,6 @@ func (z nat) mulRange(a, b uint64) nat {
        return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b))
 }
 
-// q = (x-r)/y, with 0 <= r < y
-func (z nat) divW(x nat, y Word) (q nat, r Word) {
-       m := len(x)
-       switch {
-       case y == 0:
-               panic("division by zero")
-       case y == 1:
-               q = z.set(x) // result is x
-               return
-       case m == 0:
-               q = z[:0] // result is 0
-               return
-       }
-       // m > 0
-       z = z.make(m)
-       r = divWVW(z, 0, x, y)
-       q = z.norm()
-       return
-}
-
-func (z nat) div(z2, u, v nat) (q, r nat) {
-       if len(v) == 0 {
-               panic("division by zero")
-       }
-
-       if u.cmp(v) < 0 {
-               q = z[:0]
-               r = z2.set(u)
-               return
-       }
-
-       if len(v) == 1 {
-               var r2 Word
-               q, r2 = z.divW(u, v[0])
-               r = z2.setWord(r2)
-               return
-       }
-
-       q, r = z.divLarge(z2, u, v)
-       return
-}
-
 // getNat returns a *nat of len n. The contents may not be zero.
 // The pool holds *nat to avoid allocation when converting to interface{}.
 func getNat(n int) *nat {
@@ -693,276 +651,6 @@ func putNat(x *nat) {
 
 var natPool sync.Pool
 
-// q = (uIn-r)/vIn, with 0 <= r < vIn
-// Uses z as storage for q, and u as storage for r if possible.
-// See Knuth, Volume 2, section 4.3.1, Algorithm D.
-// Preconditions:
-//    len(vIn) >= 2
-//    len(uIn) >= len(vIn)
-//    u must not alias z
-func (z nat) divLarge(u, uIn, vIn nat) (q, r nat) {
-       n := len(vIn)
-       m := len(uIn) - n
-
-       // D1.
-       shift := nlz(vIn[n-1])
-       // do not modify vIn, it may be used by another goroutine simultaneously
-       vp := getNat(n)
-       v := *vp
-       shlVU(v, vIn, shift)
-
-       // u may safely alias uIn or vIn, the value of uIn is used to set u and vIn was already used
-       u = u.make(len(uIn) + 1)
-       u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift)
-
-       // z may safely alias uIn or vIn, both values were used already
-       if alias(z, u) {
-               z = nil // z is an alias for u - cannot reuse
-       }
-       q = z.make(m + 1)
-
-       if n < divRecursiveThreshold {
-               q.divBasic(u, v)
-       } else {
-               q.divRecursive(u, v)
-       }
-       putNat(vp)
-
-       q = q.norm()
-       shrVU(u, u, shift)
-       r = u.norm()
-
-       return q, r
-}
-
-// divBasic performs word-by-word division of u by v.
-// The quotient is written in pre-allocated q.
-// The remainder overwrites input u.
-//
-// Precondition:
-// - q is large enough to hold the quotient u / v
-//   which has a maximum length of len(u)-len(v)+1.
-func (q nat) divBasic(u, v nat) {
-       n := len(v)
-       m := len(u) - n
-
-       qhatvp := getNat(n + 1)
-       qhatv := *qhatvp
-
-       // D2.
-       vn1 := v[n-1]
-       rec := reciprocalWord(vn1)
-       for j := m; j >= 0; j-- {
-               // D3.
-               qhat := Word(_M)
-               var ujn Word
-               if j+n < len(u) {
-                       ujn = u[j+n]
-               }
-               if ujn != vn1 {
-                       var rhat Word
-                       qhat, rhat = divWW(ujn, u[j+n-1], vn1, rec)
-
-                       // x1 | x2 = qÌ‚v_{n-2}
-                       vn2 := v[n-2]
-                       x1, x2 := mulWW(qhat, vn2)
-                       // test if qÌ‚v_{n-2} > brÌ‚ + u_{j+n-2}
-                       ujn2 := u[j+n-2]
-                       for greaterThan(x1, x2, rhat, ujn2) {
-                               qhat--
-                               prevRhat := rhat
-                               rhat += vn1
-                               // v[n-1] >= 0, so this tests for overflow.
-                               if rhat < prevRhat {
-                                       break
-                               }
-                               x1, x2 = mulWW(qhat, vn2)
-                       }
-               }
-
-               // D4.
-               // Compute the remainder u - (qÌ‚*v) << (_W*j).
-               // The subtraction may overflow if qÌ‚ estimate was off by one.
-               qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0)
-               qhl := len(qhatv)
-               if j+qhl > len(u) && qhatv[n] == 0 {
-                       qhl--
-               }
-               c := subVV(u[j:j+qhl], u[j:], qhatv)
-               if c != 0 {
-                       c := addVV(u[j:j+n], u[j:], v)
-                       // If n == qhl, the carry from subVV and the carry from addVV
-                       // cancel out and don't affect u[j+n].
-                       if n < qhl {
-                               u[j+n] += c
-                       }
-                       qhat--
-               }
-
-               if j == m && m == len(q) && qhat == 0 {
-                       continue
-               }
-               q[j] = qhat
-       }
-
-       putNat(qhatvp)
-}
-
-const divRecursiveThreshold = 100
-
-// divRecursive performs word-by-word division of u by v.
-// The quotient is written in pre-allocated z.
-// The remainder overwrites input u.
-//
-// Precondition:
-// - len(z) >= len(u)-len(v)
-//
-// See Burnikel, Ziegler, "Fast Recursive Division", Algorithm 1 and 2.
-func (z nat) divRecursive(u, v nat) {
-       // Recursion depth is less than 2 log2(len(v))
-       // Allocate a slice of temporaries to be reused across recursion.
-       recDepth := 2 * bits.Len(uint(len(v)))
-       // large enough to perform Karatsuba on operands as large as v
-       tmp := getNat(3 * len(v))
-       temps := make([]*nat, recDepth)
-       z.clear()
-       z.divRecursiveStep(u, v, 0, tmp, temps)
-       for _, n := range temps {
-               if n != nil {
-                       putNat(n)
-               }
-       }
-       putNat(tmp)
-}
-
-// divRecursiveStep computes the division of u by v.
-// - z must be large enough to hold the quotient
-// - the quotient will overwrite z
-// - the remainder will overwrite u
-func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) {
-       u = u.norm()
-       v = v.norm()
-
-       if len(u) == 0 {
-               z.clear()
-               return
-       }
-       n := len(v)
-       if n < divRecursiveThreshold {
-               z.divBasic(u, v)
-               return
-       }
-       m := len(u) - n
-       if m < 0 {
-               return
-       }
-
-       // Produce the quotient by blocks of B words.
-       // Division by v (length n) is done using a length n/2 division
-       // and a length n/2 multiplication for each block. The final
-       // complexity is driven by multiplication complexity.
-       B := n / 2
-
-       // Allocate a nat for qhat below.
-       if temps[depth] == nil {
-               temps[depth] = getNat(n)
-       } else {
-               *temps[depth] = temps[depth].make(B + 1)
-       }
-
-       j := m
-       for j > B {
-               // Divide u[j-B:j+n] by vIn. Keep remainder in u
-               // for next block.
-               //
-               // The following property will be used (Lemma 2):
-               // if u = u1 << s + u0
-               //    v = v1 << s + v0
-               // then floor(u1/v1) >= floor(u/v)
-               //
-               // Moreover, the difference is at most 2 if len(v1) >= len(u/v)
-               // We choose s = B-1 since len(v)-s >= B+1 >= len(u/v)
-               s := (B - 1)
-               // Except for the first step, the top bits are always
-               // a division remainder, so the quotient length is <= n.
-               uu := u[j-B:]
-
-               qhat := *temps[depth]
-               qhat.clear()
-               qhat.divRecursiveStep(uu[s:B+n], v[s:], depth+1, tmp, temps)
-               qhat = qhat.norm()
-               // Adjust the quotient:
-               //    u = u_h << s + u_l
-               //    v = v_h << s + v_l
-               //  u_h = qÌ‚ v_h + rh
-               //    u = qÌ‚ (v - v_l) + rh << s + u_l
-               // After the above step, u contains a remainder:
-               //    u = rh << s + u_l
-               // and we need to subtract qÌ‚ v_l
-               //
-               // But it may be a bit too large, in which case qÌ‚ needs to be smaller.
-               qhatv := tmp.make(3 * n)
-               qhatv.clear()
-               qhatv = qhatv.mul(qhat, v[:s])
-               for i := 0; i < 2; i++ {
-                       e := qhatv.cmp(uu.norm())
-                       if e <= 0 {
-                               break
-                       }
-                       subVW(qhat, qhat, 1)
-                       c := subVV(qhatv[:s], qhatv[:s], v[:s])
-                       if len(qhatv) > s {
-                               subVW(qhatv[s:], qhatv[s:], c)
-                       }
-                       addAt(uu[s:], v[s:], 0)
-               }
-               if qhatv.cmp(uu.norm()) > 0 {
-                       panic("impossible")
-               }
-               c := subVV(uu[:len(qhatv)], uu[:len(qhatv)], qhatv)
-               if c > 0 {
-                       subVW(uu[len(qhatv):], uu[len(qhatv):], c)
-               }
-               addAt(z, qhat, j-B)
-               j -= B
-       }
-
-       // Now u < (v<<B), compute lower bits in the same way.
-       // Choose shift = B-1 again.
-       s := B - 1
-       qhat := *temps[depth]
-       qhat.clear()
-       qhat.divRecursiveStep(u[s:].norm(), v[s:], depth+1, tmp, temps)
-       qhat = qhat.norm()
-       qhatv := tmp.make(3 * n)
-       qhatv.clear()
-       qhatv = qhatv.mul(qhat, v[:s])
-       // Set the correct remainder as before.
-       for i := 0; i < 2; i++ {
-               if e := qhatv.cmp(u.norm()); e > 0 {
-                       subVW(qhat, qhat, 1)
-                       c := subVV(qhatv[:s], qhatv[:s], v[:s])
-                       if len(qhatv) > s {
-                               subVW(qhatv[s:], qhatv[s:], c)
-                       }
-                       addAt(u[s:], v[s:], 0)
-               }
-       }
-       if qhatv.cmp(u.norm()) > 0 {
-               panic("impossible")
-       }
-       c := subVV(u[0:len(qhatv)], u[0:len(qhatv)], qhatv)
-       if c > 0 {
-               c = subVW(u[len(qhatv):], u[len(qhatv):], c)
-       }
-       if c > 0 {
-               panic("impossible")
-       }
-
-       // Done!
-       addAt(z, qhat.norm(), 0)
-}
-
 // Length of x in bits. x must be normalized.
 func (x nat) bitLen() int {
        if i := len(x) - 1; i >= 0 {
@@ -1170,19 +858,6 @@ func (z nat) xor(x, y nat) nat {
        return z.norm()
 }
 
-// greaterThan reports whether (x1<<_W + x2) > (y1<<_W + y2)
-func greaterThan(x1, x2, y1, y2 Word) bool {
-       return x1 > y1 || x1 == y1 && x2 > y2
-}
-
-// modW returns x % d.
-func (x nat) modW(d Word) (r Word) {
-       // TODO(agl): we don't actually need to store the q value.
-       var q nat
-       q = q.make(len(x))
-       return divWVW(q, 0, x, d)
-}
-
 // random creates a random integer in [0..limit), using the space in z if
 // possible. n is the bit length of limit.
 func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
diff --git a/src/math/big/natdiv.go b/src/math/big/natdiv.go
new file mode 100644 (file)
index 0000000..1330990
--- /dev/null
@@ -0,0 +1,346 @@
+// Copyright 2009 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 big
+
+import "math/bits"
+
+func (z nat) div(z2, u, v nat) (q, r nat) {
+       if len(v) == 0 {
+               panic("division by zero")
+       }
+
+       if u.cmp(v) < 0 {
+               q = z[:0]
+               r = z2.set(u)
+               return
+       }
+
+       if len(v) == 1 {
+               var r2 Word
+               q, r2 = z.divW(u, v[0])
+               r = z2.setWord(r2)
+               return
+       }
+
+       q, r = z.divLarge(z2, u, v)
+       return
+}
+
+// q = (x-r)/y, with 0 <= r < y
+func (z nat) divW(x nat, y Word) (q nat, r Word) {
+       m := len(x)
+       switch {
+       case y == 0:
+               panic("division by zero")
+       case y == 1:
+               q = z.set(x) // result is x
+               return
+       case m == 0:
+               q = z[:0] // result is 0
+               return
+       }
+       // m > 0
+       z = z.make(m)
+       r = divWVW(z, 0, x, y)
+       q = z.norm()
+       return
+}
+
+// modW returns x % d.
+func (x nat) modW(d Word) (r Word) {
+       // TODO(agl): we don't actually need to store the q value.
+       var q nat
+       q = q.make(len(x))
+       return divWVW(q, 0, x, d)
+}
+
+func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) {
+       r = xn
+       if len(x) == 1 {
+               qq, rr := bits.Div(uint(r), uint(x[0]), uint(y))
+               z[0] = Word(qq)
+               return Word(rr)
+       }
+       rec := reciprocalWord(y)
+       for i := len(z) - 1; i >= 0; i-- {
+               z[i], r = divWW(r, x[i], y, rec)
+       }
+       return r
+}
+
+// q = (uIn-r)/vIn, with 0 <= r < vIn
+// Uses z as storage for q, and u as storage for r if possible.
+// See Knuth, Volume 2, section 4.3.1, Algorithm D.
+// Preconditions:
+//    len(vIn) >= 2
+//    len(uIn) >= len(vIn)
+//    u must not alias z
+func (z nat) divLarge(u, uIn, vIn nat) (q, r nat) {
+       n := len(vIn)
+       m := len(uIn) - n
+
+       // D1.
+       shift := nlz(vIn[n-1])
+       // do not modify vIn, it may be used by another goroutine simultaneously
+       vp := getNat(n)
+       v := *vp
+       shlVU(v, vIn, shift)
+
+       // u may safely alias uIn or vIn, the value of uIn is used to set u and vIn was already used
+       u = u.make(len(uIn) + 1)
+       u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift)
+
+       // z may safely alias uIn or vIn, both values were used already
+       if alias(z, u) {
+               z = nil // z is an alias for u - cannot reuse
+       }
+       q = z.make(m + 1)
+
+       if n < divRecursiveThreshold {
+               q.divBasic(u, v)
+       } else {
+               q.divRecursive(u, v)
+       }
+       putNat(vp)
+
+       q = q.norm()
+       shrVU(u, u, shift)
+       r = u.norm()
+
+       return q, r
+}
+
+// divBasic performs word-by-word division of u by v.
+// The quotient is written in pre-allocated q.
+// The remainder overwrites input u.
+//
+// Precondition:
+// - q is large enough to hold the quotient u / v
+//   which has a maximum length of len(u)-len(v)+1.
+func (q nat) divBasic(u, v nat) {
+       n := len(v)
+       m := len(u) - n
+
+       qhatvp := getNat(n + 1)
+       qhatv := *qhatvp
+
+       // D2.
+       vn1 := v[n-1]
+       rec := reciprocalWord(vn1)
+       for j := m; j >= 0; j-- {
+               // D3.
+               qhat := Word(_M)
+               var ujn Word
+               if j+n < len(u) {
+                       ujn = u[j+n]
+               }
+               if ujn != vn1 {
+                       var rhat Word
+                       qhat, rhat = divWW(ujn, u[j+n-1], vn1, rec)
+
+                       // x1 | x2 = qÌ‚v_{n-2}
+                       vn2 := v[n-2]
+                       x1, x2 := mulWW(qhat, vn2)
+                       // test if qÌ‚v_{n-2} > brÌ‚ + u_{j+n-2}
+                       ujn2 := u[j+n-2]
+                       for greaterThan(x1, x2, rhat, ujn2) {
+                               qhat--
+                               prevRhat := rhat
+                               rhat += vn1
+                               // v[n-1] >= 0, so this tests for overflow.
+                               if rhat < prevRhat {
+                                       break
+                               }
+                               x1, x2 = mulWW(qhat, vn2)
+                       }
+               }
+
+               // D4.
+               // Compute the remainder u - (qÌ‚*v) << (_W*j).
+               // The subtraction may overflow if qÌ‚ estimate was off by one.
+               qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0)
+               qhl := len(qhatv)
+               if j+qhl > len(u) && qhatv[n] == 0 {
+                       qhl--
+               }
+               c := subVV(u[j:j+qhl], u[j:], qhatv)
+               if c != 0 {
+                       c := addVV(u[j:j+n], u[j:], v)
+                       // If n == qhl, the carry from subVV and the carry from addVV
+                       // cancel out and don't affect u[j+n].
+                       if n < qhl {
+                               u[j+n] += c
+                       }
+                       qhat--
+               }
+
+               if j == m && m == len(q) && qhat == 0 {
+                       continue
+               }
+               q[j] = qhat
+       }
+
+       putNat(qhatvp)
+}
+
+// greaterThan reports whether (x1<<_W + x2) > (y1<<_W + y2)
+func greaterThan(x1, x2, y1, y2 Word) bool {
+       return x1 > y1 || x1 == y1 && x2 > y2
+}
+
+const divRecursiveThreshold = 100
+
+// divRecursive performs word-by-word division of u by v.
+// The quotient is written in pre-allocated z.
+// The remainder overwrites input u.
+//
+// Precondition:
+// - len(z) >= len(u)-len(v)
+//
+// See Burnikel, Ziegler, "Fast Recursive Division", Algorithm 1 and 2.
+func (z nat) divRecursive(u, v nat) {
+       // Recursion depth is less than 2 log2(len(v))
+       // Allocate a slice of temporaries to be reused across recursion.
+       recDepth := 2 * bits.Len(uint(len(v)))
+       // large enough to perform Karatsuba on operands as large as v
+       tmp := getNat(3 * len(v))
+       temps := make([]*nat, recDepth)
+       z.clear()
+       z.divRecursiveStep(u, v, 0, tmp, temps)
+       for _, n := range temps {
+               if n != nil {
+                       putNat(n)
+               }
+       }
+       putNat(tmp)
+}
+
+// divRecursiveStep computes the division of u by v.
+// - z must be large enough to hold the quotient
+// - the quotient will overwrite z
+// - the remainder will overwrite u
+func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) {
+       u = u.norm()
+       v = v.norm()
+
+       if len(u) == 0 {
+               z.clear()
+               return
+       }
+       n := len(v)
+       if n < divRecursiveThreshold {
+               z.divBasic(u, v)
+               return
+       }
+       m := len(u) - n
+       if m < 0 {
+               return
+       }
+
+       // Produce the quotient by blocks of B words.
+       // Division by v (length n) is done using a length n/2 division
+       // and a length n/2 multiplication for each block. The final
+       // complexity is driven by multiplication complexity.
+       B := n / 2
+
+       // Allocate a nat for qhat below.
+       if temps[depth] == nil {
+               temps[depth] = getNat(n)
+       } else {
+               *temps[depth] = temps[depth].make(B + 1)
+       }
+
+       j := m
+       for j > B {
+               // Divide u[j-B:j+n] by vIn. Keep remainder in u
+               // for next block.
+               //
+               // The following property will be used (Lemma 2):
+               // if u = u1 << s + u0
+               //    v = v1 << s + v0
+               // then floor(u1/v1) >= floor(u/v)
+               //
+               // Moreover, the difference is at most 2 if len(v1) >= len(u/v)
+               // We choose s = B-1 since len(v)-s >= B+1 >= len(u/v)
+               s := (B - 1)
+               // Except for the first step, the top bits are always
+               // a division remainder, so the quotient length is <= n.
+               uu := u[j-B:]
+
+               qhat := *temps[depth]
+               qhat.clear()
+               qhat.divRecursiveStep(uu[s:B+n], v[s:], depth+1, tmp, temps)
+               qhat = qhat.norm()
+               // Adjust the quotient:
+               //    u = u_h << s + u_l
+               //    v = v_h << s + v_l
+               //  u_h = qÌ‚ v_h + rh
+               //    u = qÌ‚ (v - v_l) + rh << s + u_l
+               // After the above step, u contains a remainder:
+               //    u = rh << s + u_l
+               // and we need to subtract qÌ‚ v_l
+               //
+               // But it may be a bit too large, in which case qÌ‚ needs to be smaller.
+               qhatv := tmp.make(3 * n)
+               qhatv.clear()
+               qhatv = qhatv.mul(qhat, v[:s])
+               for i := 0; i < 2; i++ {
+                       e := qhatv.cmp(uu.norm())
+                       if e <= 0 {
+                               break
+                       }
+                       subVW(qhat, qhat, 1)
+                       c := subVV(qhatv[:s], qhatv[:s], v[:s])
+                       if len(qhatv) > s {
+                               subVW(qhatv[s:], qhatv[s:], c)
+                       }
+                       addAt(uu[s:], v[s:], 0)
+               }
+               if qhatv.cmp(uu.norm()) > 0 {
+                       panic("impossible")
+               }
+               c := subVV(uu[:len(qhatv)], uu[:len(qhatv)], qhatv)
+               if c > 0 {
+                       subVW(uu[len(qhatv):], uu[len(qhatv):], c)
+               }
+               addAt(z, qhat, j-B)
+               j -= B
+       }
+
+       // Now u < (v<<B), compute lower bits in the same way.
+       // Choose shift = B-1 again.
+       s := B - 1
+       qhat := *temps[depth]
+       qhat.clear()
+       qhat.divRecursiveStep(u[s:].norm(), v[s:], depth+1, tmp, temps)
+       qhat = qhat.norm()
+       qhatv := tmp.make(3 * n)
+       qhatv.clear()
+       qhatv = qhatv.mul(qhat, v[:s])
+       // Set the correct remainder as before.
+       for i := 0; i < 2; i++ {
+               if e := qhatv.cmp(u.norm()); e > 0 {
+                       subVW(qhat, qhat, 1)
+                       c := subVV(qhatv[:s], qhatv[:s], v[:s])
+                       if len(qhatv) > s {
+                               subVW(qhatv[s:], qhatv[s:], c)
+                       }
+                       addAt(u[s:], v[s:], 0)
+               }
+       }
+       if qhatv.cmp(u.norm()) > 0 {
+               panic("impossible")
+       }
+       c := subVV(u[0:len(qhatv)], u[0:len(qhatv)], qhatv)
+       if c > 0 {
+               c = subVW(u[len(qhatv):], u[len(qhatv):], c)
+       }
+       if c > 0 {
+               panic("impossible")
+       }
+
+       // Done!
+       addAt(z, qhat.norm(), 0)
+}
index 9bbbf216a1d1d96fc35ba6c2e1e4d569b361fb8b..26424339af8d03b319c5dbb870f3562e80cde891 100644 (file)
@@ -96,9 +96,11 @@ func initMime() {
 // Extensions are looked up first case-sensitively, then case-insensitively.
 //
 // The built-in table is small but on unix it is augmented by the local
-// system's mime.types file(s) if available under one or more of these
-// names:
+// system's MIME-info database or mime.types file(s) if available under one or
+// more of these names:
 //
+//   /usr/local/share/mime/globs2
+//   /usr/share/mime/globs2
 //   /etc/mime.types
 //   /etc/apache2/mime.types
 //   /etc/apache/mime.types
index 69a9b972f0868b79b9a678ac0a40d949469a3c16..a718e75a726af486d621d48edd14d888ab6cc834 100644 (file)
@@ -1893,30 +1893,66 @@ func TestCVE202133195(t *testing.T) {
                        return r, nil
                },
        }
+
        r := Resolver{PreferGo: true, Dial: fake.DialContext}
+       // Change the default resolver to match our manipulated resolver
+       originalDefault := DefaultResolver
+       DefaultResolver = &r
+       defer func() {
+               DefaultResolver = originalDefault
+       }()
 
        _, err := r.LookupCNAME(context.Background(), "golang.org")
-       if expected := "lookup golang.org: CNAME target is invalid"; err.Error() != expected {
+       if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
+               t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected)
+       }
+       _, err = LookupCNAME("golang.org")
+       if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
                t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected)
        }
+
        _, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org")
-       if expected := "lookup golang.org: SRV target is invalid"; err.Error() != expected {
+       if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected {
+               t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected)
+       }
+       _, _, err = LookupSRV("target", "tcp", "golang.org")
+       if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected {
                t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected)
        }
+
        _, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org")
-       if expected := "lookup golang.org: SRV header name is invalid"; err.Error() != expected {
+       if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected {
+               t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected)
+       }
+       _, _, err = LookupSRV("hdr", "tcp", "golang.org")
+       if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected {
                t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected)
        }
+
        _, err = r.LookupMX(context.Background(), "golang.org")
-       if expected := "lookup golang.org: MX target is invalid"; err.Error() != expected {
+       if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected {
+               t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err.Error(), expected)
+       }
+       _, err = LookupMX("golang.org")
+       if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected {
                t.Errorf("LookupMX returned unexpected error, got %q, want %q", err.Error(), expected)
        }
+
        _, err = r.LookupNS(context.Background(), "golang.org")
-       if expected := "lookup golang.org: NS target is invalid"; err.Error() != expected {
+       if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected {
+               t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err.Error(), expected)
+       }
+       _, err = LookupNS("golang.org")
+       if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected {
                t.Errorf("LookupNS returned unexpected error, got %q, want %q", err.Error(), expected)
        }
+
        _, err = r.LookupAddr(context.Background(), "1.2.3.4")
-       if expected := "lookup 1.2.3.4: PTR target is invalid"; err.Error() != expected {
+       if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected {
+               t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected)
+       }
+       _, err = LookupAddr("1.2.3.4")
+       if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected {
                t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected)
        }
 }
index 03c9155fbdd79e4bd85824de1fd92a2e29c3dcf4..e0cabc9d4cf38143fdf5b406b1e5707a4ea4a5bf 100644 (file)
@@ -433,8 +433,7 @@ func basicAuth(username, password string) string {
 // An error is returned if there were too many redirects or if there
 // was an HTTP protocol error. A non-2xx response doesn't cause an
 // error. Any returned error will be of type *url.Error. The url.Error
-// value's Timeout method will report true if request timed out or was
-// canceled.
+// value's Timeout method will report true if the request timed out.
 //
 // When err is nil, resp always contains a non-nil resp.Body.
 // Caller should close resp.Body when done reading from it.
@@ -589,8 +588,7 @@ func urlErrorOp(method string) string {
 // standard library body types.
 //
 // Any returned error will be of type *url.Error. The url.Error
-// value's Timeout method will report true if request timed out or was
-// canceled.
+// value's Timeout method will report true if the request timed out.
 func (c *Client) Do(req *Request) (*Response, error) {
        return c.do(req)
 }
@@ -729,7 +727,6 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
                        reqBodyClosed = true
                        if !deadline.IsZero() && didTimeout() {
                                err = &httpError{
-                                       // TODO: early in cycle: s/Client.Timeout exceeded/timeout or context cancellation/
                                        err:     err.Error() + " (Client.Timeout exceeded while awaiting headers)",
                                        timeout: true,
                                }
index 1432ee26d37f19ef57380dac19be899b584bc375..5d39955d62d15fa962f8ead218e93a620af49a13 100644 (file)
@@ -253,22 +253,18 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
        // important is "Connection" because we want a persistent
        // connection, regardless of what the client sent to us.
        for _, h := range hopHeaders {
-               hv := outreq.Header.Get(h)
-               if hv == "" {
-                       continue
-               }
-               if h == "Te" && hv == "trailers" {
-                       // Issue 21096: tell backend applications that
-                       // care about trailer support that we support
-                       // trailers. (We do, but we don't go out of
-                       // our way to advertise that unless the
-                       // incoming client request thought it was
-                       // worth mentioning)
-                       continue
-               }
                outreq.Header.Del(h)
        }
 
+       // Issue 21096: tell backend applications that care about trailer support
+       // that we support trailers. (We do, but we don't go out of our way to
+       // advertise that unless the incoming client request thought it was worth
+       // mentioning.) Note that we look at req.Header, not outreq.Header, since
+       // the latter has passed through removeConnectionHeaders.
+       if httpguts.HeaderValuesContainsToken(req.Header["Te"], "trailers") {
+               outreq.Header.Set("Te", "trailers")
+       }
+
        // After stripping all the hop-by-hop connection headers above, add back any
        // necessary for protocol upgrades, such as for websockets.
        if reqUpType != "" {
index 22720caf930f2f167fa80c16fd3007793bf693dd..1898ed8b8afdef4a1e0da64daa1c0cd480070483 100644 (file)
@@ -91,8 +91,9 @@ func TestReverseProxy(t *testing.T) {
 
        getReq, _ := http.NewRequest("GET", frontend.URL, nil)
        getReq.Host = "some-name"
-       getReq.Header.Set("Connection", "close")
-       getReq.Header.Set("Te", "trailers")
+       getReq.Header.Set("Connection", "close, TE")
+       getReq.Header.Add("Te", "foo")
+       getReq.Header.Add("Te", "bar, trailers")
        getReq.Header.Set("Proxy-Connection", "should be deleted")
        getReq.Header.Set("Upgrade", "foo")
        getReq.Close = true
@@ -236,6 +237,64 @@ func TestReverseProxyStripHeadersPresentInConnection(t *testing.T) {
        }
 }
 
+func TestReverseProxyStripEmptyConnection(t *testing.T) {
+       // See Issue 46313.
+       const backendResponse = "I am the backend"
+
+       // someConnHeader is some arbitrary header to be declared as a hop-by-hop header
+       // in the Request's Connection header.
+       const someConnHeader = "X-Some-Conn-Header"
+
+       backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               if c := r.Header.Values("Connection"); len(c) != 0 {
+                       t.Errorf("handler got header %q = %v; want empty", "Connection", c)
+               }
+               if c := r.Header.Get(someConnHeader); c != "" {
+                       t.Errorf("handler got header %q = %q; want empty", someConnHeader, c)
+               }
+               w.Header().Add("Connection", "")
+               w.Header().Add("Connection", someConnHeader)
+               w.Header().Set(someConnHeader, "should be deleted")
+               io.WriteString(w, backendResponse)
+       }))
+       defer backend.Close()
+       backendURL, err := url.Parse(backend.URL)
+       if err != nil {
+               t.Fatal(err)
+       }
+       proxyHandler := NewSingleHostReverseProxy(backendURL)
+       frontend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               proxyHandler.ServeHTTP(w, r)
+               if c := r.Header.Get(someConnHeader); c != "should be deleted" {
+                       t.Errorf("handler modified header %q = %q; want %q", someConnHeader, c, "should be deleted")
+               }
+       }))
+       defer frontend.Close()
+
+       getReq, _ := http.NewRequest("GET", frontend.URL, nil)
+       getReq.Header.Add("Connection", "")
+       getReq.Header.Add("Connection", someConnHeader)
+       getReq.Header.Set(someConnHeader, "should be deleted")
+       res, err := frontend.Client().Do(getReq)
+       if err != nil {
+               t.Fatalf("Get: %v", err)
+       }
+       defer res.Body.Close()
+       bodyBytes, err := io.ReadAll(res.Body)
+       if err != nil {
+               t.Fatalf("reading body: %v", err)
+       }
+       if got, want := string(bodyBytes), backendResponse; got != want {
+               t.Errorf("got body %q; want %q", got, want)
+       }
+       if c := res.Header.Get("Connection"); c != "" {
+               t.Errorf("handler got header %q = %q; want empty", "Connection", c)
+       }
+       if c := res.Header.Get(someConnHeader); c != "" {
+               t.Errorf("handler got header %q = %q; want empty", someConnHeader, c)
+       }
+}
+
 func TestXForwardedFor(t *testing.T) {
        const prevForwardedFor = "client ip"
        const backendResponse = "I am the backend"
index 39d33796d5b3edc80a0128a7bf7881711053dd24..02a4cdcd1ee2f651703d6e1b48e6826c06f3457a 100644 (file)
@@ -402,7 +402,7 @@ func (r *Resolver) LookupPort(ctx context.Context, network, service string) (por
 // LookupCNAME uses context.Background internally; to specify the context, use
 // Resolver.LookupCNAME.
 func LookupCNAME(host string) (cname string, err error) {
-       return DefaultResolver.lookupCNAME(context.Background(), host)
+       return DefaultResolver.LookupCNAME(context.Background(), host)
 }
 
 // LookupCNAME returns the canonical name for the given host.
@@ -442,7 +442,7 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error)
 // The returned service names are validated to be properly
 // formatted presentation-format domain names.
 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
-       return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
+       return DefaultResolver.LookupSRV(context.Background(), service, proto, name)
 }
 
 // LookupSRV tries to resolve an SRV query of the given service,
@@ -484,7 +484,7 @@ func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (
 // LookupMX uses context.Background internally; to specify the context, use
 // Resolver.LookupMX.
 func LookupMX(name string) ([]*MX, error) {
-       return DefaultResolver.lookupMX(context.Background(), name)
+       return DefaultResolver.LookupMX(context.Background(), name)
 }
 
 // LookupMX returns the DNS MX records for the given domain name sorted by preference.
@@ -515,7 +515,7 @@ func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
 // LookupNS uses context.Background internally; to specify the context, use
 // Resolver.LookupNS.
 func LookupNS(name string) ([]*NS, error) {
-       return DefaultResolver.lookupNS(context.Background(), name)
+       return DefaultResolver.LookupNS(context.Background(), name)
 }
 
 // LookupNS returns the DNS NS records for the given domain name.
@@ -554,20 +554,23 @@ func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error)
 // LookupAddr performs a reverse lookup for the given address, returning a list
 // of names mapping to that address.
 //
+// The returned names are validated to be properly formatted presentation-format
+// domain names.
+//
 // When using the host C library resolver, at most one result will be
 // returned. To bypass the host resolver, use a custom Resolver.
 //
 // LookupAddr uses context.Background internally; to specify the context, use
 // Resolver.LookupAddr.
 func LookupAddr(addr string) (names []string, err error) {
-       return DefaultResolver.lookupAddr(context.Background(), addr)
+       return DefaultResolver.LookupAddr(context.Background(), addr)
 }
 
 // LookupAddr performs a reverse lookup for the given address, returning a list
 // of names mapping to that address.
 //
-// The returned names are validated to be properly
-// formatted presentation-format domain names.
+// The returned names are validated to be properly formatted presentation-format
+// domain names.
 func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
        names, err := r.lookupAddr(ctx, addr)
        if err != nil {
index b6636185029c5f24a3353c41976843fdd6c110c4..41a1e9c78aa36542a892392b63ae136cfd3403be 100644 (file)
@@ -442,12 +442,14 @@ func TestFdReadRace(t *testing.T) {
        defer r.Close()
        defer w.Close()
 
-       c := make(chan bool)
+       const count = 10
+
+       c := make(chan bool, 1)
        var wg sync.WaitGroup
        wg.Add(1)
        go func() {
                defer wg.Done()
-               var buf [10]byte
+               var buf [count]byte
                r.SetReadDeadline(time.Now().Add(time.Minute))
                c <- true
                if _, err := r.Read(buf[:]); os.IsTimeout(err) {
@@ -466,8 +468,9 @@ func TestFdReadRace(t *testing.T) {
                r.Fd()
 
                // The bug was that Fd would hang until Read timed out.
-               // If the bug is fixed, then closing r here will cause
-               // the Read to exit before the timeout expires.
+               // If the bug is fixed, then writing to w and closing r here
+               // will cause the Read to exit before the timeout expires.
+               w.Write(make([]byte, count))
                r.Close()
        }()
 
index 81e522588301f92d57feb9dbc5d34b93b72ad6f4..2759bbdaf90f5539a06197728d7fa8476bf89e64 100644 (file)
@@ -296,7 +296,7 @@ const (
        // high addresses if viewed as unsigned).
        //
        // On aix/ppc64, this offset allows to keep the heapAddrBits to
-       // 48. Otherwize, it would be 60 in order to handle mmap addresses
+       // 48. Otherwise, it would be 60 in order to handle mmap addresses
        // (in range 0x0a00000000000000 - 0x0afffffffffffff). But in this
        // case, the memory reserved in (s *pageAlloc).init for chunks
        // is causing important slowdowns.