[dev.boringcrypto] all: merge master into dev.boringcrypto

Change-Id: I0f610a900fcd5575ca12b34bc74fa63c2146b10b
This commit is contained in:
Filippo Valsorda 2019-05-22 14:04:16 -04:00
commit e48f228c9b
2657 changed files with 399109 additions and 114405 deletions

View file

@ -928,6 +928,7 @@ Maxim Khitrov <max@mxcrypt.com>
Maxime de Roucy <maxime.deroucy@gmail.com> Maxime de Roucy <maxime.deroucy@gmail.com>
Máximo Cuadros Ortiz <mcuadros@gmail.com> Máximo Cuadros Ortiz <mcuadros@gmail.com>
Maxwell Krohn <themax@gmail.com> Maxwell Krohn <themax@gmail.com>
Maya Rashish <maya@netbsd.org>
Mayank Kumar <krmayankk@gmail.com> Mayank Kumar <krmayankk@gmail.com>
MediaMath, Inc MediaMath, Inc
Meir Fischer <meirfischer@gmail.com> Meir Fischer <meirfischer@gmail.com>

View file

@ -457,4 +457,5 @@ pkg syscall (freebsd-arm-cgo), type Stat_t struct, Nlink uint16
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Rdev uint32 pkg syscall (freebsd-arm-cgo), type Stat_t struct, Rdev uint32
pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntfromname [88]int8 pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntfromname [88]int8
pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntonname [88]int8 pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntonname [88]int8
pkg text/scanner, const GoTokens = 1012 pkg text/scanner, const GoTokens = 1012
pkg unicode, const Version = "10.0.0"

File diff suppressed because it is too large Load diff

View file

@ -57,59 +57,66 @@ func main() {
println(3) println(3)
} }
$ GOOS=linux GOARCH=amd64 go tool compile -S x.go # or: go build -gcflags -S x.go $ GOOS=linux GOARCH=amd64 go tool compile -S x.go # or: go build -gcflags -S x.go
"".main STEXT size=74 args=0x0 locals=0x10
--- prog list "main" --- 0x0000 00000 (x.go:3) TEXT "".main(SB), $16-0
0000 (x.go:3) TEXT main+0(SB),$8-0 0x0000 00000 (x.go:3) MOVQ (TLS), CX
0001 (x.go:3) FUNCDATA $0,gcargs·0+0(SB) 0x0009 00009 (x.go:3) CMPQ SP, 16(CX)
0002 (x.go:3) FUNCDATA $1,gclocals·0+0(SB) 0x000d 00013 (x.go:3) JLS 67
0003 (x.go:4) MOVQ $3,(SP) 0x000f 00015 (x.go:3) SUBQ $16, SP
0004 (x.go:4) PCDATA $0,$8 0x0013 00019 (x.go:3) MOVQ BP, 8(SP)
0005 (x.go:4) CALL ,runtime.printint+0(SB) 0x0018 00024 (x.go:3) LEAQ 8(SP), BP
0006 (x.go:4) PCDATA $0,$-1 0x001d 00029 (x.go:3) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0007 (x.go:4) PCDATA $0,$0 0x001d 00029 (x.go:3) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0008 (x.go:4) CALL ,runtime.printnl+0(SB) 0x001d 00029 (x.go:3) FUNCDATA $2, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0009 (x.go:4) PCDATA $0,$-1 0x001d 00029 (x.go:4) PCDATA $0, $0
0010 (x.go:5) RET , 0x001d 00029 (x.go:4) PCDATA $1, $0
0x001d 00029 (x.go:4) CALL runtime.printlock(SB)
0x0022 00034 (x.go:4) MOVQ $3, (SP)
0x002a 00042 (x.go:4) CALL runtime.printint(SB)
0x002f 00047 (x.go:4) CALL runtime.printnl(SB)
0x0034 00052 (x.go:4) CALL runtime.printunlock(SB)
0x0039 00057 (x.go:5) MOVQ 8(SP), BP
0x003e 00062 (x.go:5) ADDQ $16, SP
0x0042 00066 (x.go:5) RET
0x0043 00067 (x.go:5) NOP
0x0043 00067 (x.go:3) PCDATA $1, $-1
0x0043 00067 (x.go:3) PCDATA $0, $-1
0x0043 00067 (x.go:3) CALL runtime.morestack_noctxt(SB)
0x0048 00072 (x.go:3) JMP 0
... ...
</pre> </pre>
<p> <p>
The <code>FUNCDATA</code> and <code>PCDATA</code> directives contain information The <code>FUNCDATA</code> and <code>PCDATA</code> directives contain information
for use by the garbage collector; they are introduced by the compiler. for use by the garbage collector; they are introduced by the compiler.
</p> </p>
<!-- Commenting out because the feature is gone but it's popular and may come back.
<p> <p>
To see what gets put in the binary after linking, add the <code>-a</code> flag to the linker: To see what gets put in the binary after linking, use <code>go tool objdump</code>:
</p> </p>
<pre> <pre>
$ go tool 6l -a x.6 # or: go build -ldflags -a x.go $ go build -o x.exe x.go
codeblk [0x2000,0x1d059) at offset 0x1000 $ go tool objdump -s main.main x.exe
002000 main.main | (3) TEXT main.main+0(SB),$8 TEXT main.main(SB) /tmp/x.go
002000 65488b0c25a0080000 | (3) MOVQ 2208(GS),CX x.go:3 0x10501c0 65488b0c2530000000 MOVQ GS:0x30, CX
002009 483b21 | (3) CMPQ SP,(CX) x.go:3 0x10501c9 483b6110 CMPQ 0x10(CX), SP
00200c 7707 | (3) JHI ,2015 x.go:3 0x10501cd 7634 JBE 0x1050203
00200e e83da20100 | (3) CALL ,1c250+runtime.morestack00 x.go:3 0x10501cf 4883ec10 SUBQ $0x10, SP
002013 ebeb | (3) JMP ,2000 x.go:3 0x10501d3 48896c2408 MOVQ BP, 0x8(SP)
002015 4883ec08 | (3) SUBQ $8,SP x.go:3 0x10501d8 488d6c2408 LEAQ 0x8(SP), BP
002019 | (3) FUNCDATA $0,main.gcargs·0+0(SB) x.go:4 0x10501dd e86e45fdff CALL runtime.printlock(SB)
002019 | (3) FUNCDATA $1,main.gclocals·0+0(SB) x.go:4 0x10501e2 48c7042403000000 MOVQ $0x3, 0(SP)
002019 48c7042403000000 | (4) MOVQ $3,(SP) x.go:4 0x10501ea e8e14cfdff CALL runtime.printint(SB)
002021 | (4) PCDATA $0,$8 x.go:4 0x10501ef e8ec47fdff CALL runtime.printnl(SB)
002021 e8aad20000 | (4) CALL ,f2d0+runtime.printint x.go:4 0x10501f4 e8d745fdff CALL runtime.printunlock(SB)
002026 | (4) PCDATA $0,$-1 x.go:5 0x10501f9 488b6c2408 MOVQ 0x8(SP), BP
002026 | (4) PCDATA $0,$0 x.go:5 0x10501fe 4883c410 ADDQ $0x10, SP
002026 e865d40000 | (4) CALL ,f490+runtime.printnl x.go:5 0x1050202 c3 RET
00202b | (4) PCDATA $0,$-1 x.go:3 0x1050203 e83882ffff CALL runtime.morestack_noctxt(SB)
00202b 4883c408 | (5) ADDQ $8,SP x.go:3 0x1050208 ebb6 JMP main.main(SB)
00202f c3 | (5) RET ,
...
</pre> </pre>
-->
<h3 id="constants">Constants</h3> <h3 id="constants">Constants</h3>
<p> <p>
@ -266,7 +273,7 @@ that assembly programming is a fraught endeavor.
</p> </p>
<p> <p>
In Go object files and binaries, the full name of a symbol is the In Go object files and binaries, the full name of a symbol is the
package path followed by a period and the symbol name: package path followed by a period and the symbol name:
<code>fmt.Printf</code> or <code>math/rand.Int</code>. <code>fmt.Printf</code> or <code>math/rand.Int</code>.
Because the assembler's parser treats period and slash as punctuation, Because the assembler's parser treats period and slash as punctuation,
@ -485,7 +492,7 @@ even for assembly functions not called directly from Go.
At the start of the function, the arguments are assumed At the start of the function, the arguments are assumed
to be initialized but the results are assumed uninitialized. to be initialized but the results are assumed uninitialized.
If the results will hold live pointers during a call instruction, If the results will hold live pointers during a call instruction,
the function should start by zeroing the results and then the function should start by zeroing the results and then
executing the pseudo-instruction <code>GO_RESULTS_INITIALIZED</code>. executing the pseudo-instruction <code>GO_RESULTS_INITIALIZED</code>.
This instruction records that the results are now initialized This instruction records that the results are now initialized
and should be scanned during stack movement and garbage collection. and should be scanned during stack movement and garbage collection.
@ -503,7 +510,7 @@ on the <code>TEXT</code> instruction.
The pointer information can also be omitted if the The pointer information can also be omitted if the
function contains no call instructions. function contains no call instructions.
Otherwise, the local stack frame must not contain pointers, Otherwise, the local stack frame must not contain pointers,
and the assembly must confirm this fact by executing the and the assembly must confirm this fact by executing the
pseudo-instruction <code>NO_LOCAL_POINTERS</code>. pseudo-instruction <code>NO_LOCAL_POINTERS</code>.
Because stack resizing is implemented by moving the stack, Because stack resizing is implemented by moving the stack,
the stack pointer may change during any function call: the stack pointer may change during any function call:

View file

@ -304,12 +304,12 @@ optional: you do not need to use source control to write Go code.
<pre> <pre>
$ <b>cd $GOPATH/src/github.com/user/hello</b> $ <b>cd $GOPATH/src/github.com/user/hello</b>
$ <b>git init</b> $ <b>git init</b>
Initialized empty Git repository in /home/user/work/src/github.com/user/hello/.git/ Initialized empty Git repository in /home/user/go/src/github.com/user/hello/.git/
$ <b>git add hello.go</b> $ <b>git add hello.go</b>
$ <b>git commit -m "initial commit"</b> $ <b>git commit -m "initial commit"</b>
[master (root-commit) 0b4507d] initial commit [master (root-commit) 0b4507d] initial commit
1 file changed, 1 insertion(+) 1 file changed, 7 insertion(+)
create mode 100644 hello.go create mode 100644 hello.go
</pre> </pre>
<p> <p>

View file

@ -46,7 +46,8 @@ CLA (Contributor License Agreement).
<li> <li>
<b>Step 2</b>: Configure authentication credentials for the Go Git repository. <b>Step 2</b>: Configure authentication credentials for the Go Git repository.
Visit <a href="https://go.googlesource.com/">go.googlesource.com</a>, click Visit <a href="https://go.googlesource.com/">go.googlesource.com</a>, click
on "Generate Password" (top right), and follow the instructions. on the gear icon (top right), then on "Obtain password", and follow the
instructions.
</li> </li>
<li> <li>
<b>Step 3</b>: Register for Gerrit, the code review tool used by the Go team, <b>Step 3</b>: Register for Gerrit, the code review tool used by the Go team,

View file

@ -149,6 +149,9 @@ Inspecting goroutines:
(gdb) <b>help goroutine</b></pre> (gdb) <b>help goroutine</b></pre>
For example: For example:
<pre>(gdb) <b>goroutine 12 bt</b></pre> <pre>(gdb) <b>goroutine 12 bt</b></pre>
You can inspect all goroutines by passing <code>all</code> instead of a specific goroutine's ID.
For example:
<pre>(gdb) <b>goroutine all bt</b></pre>
</li> </li>
</ul> </ul>

View file

@ -30,6 +30,45 @@ Go 1.12 is a major release of Go.
Read the <a href="/doc/go1.12">Go 1.12 Release Notes</a> for more information. Read the <a href="/doc/go1.12">Go 1.12 Release Notes</a> for more information.
</p> </p>
<h3 id="go1.12.minor">Minor revisions</h3>
<p>
go1.12.1 (released 2019/03/14) includes fixes to cgo, the compiler, the go
command, and the <code>fmt</code>, <code>net/smtp</code>, <code>os</code>,
<code>path/filepath</code>, <code>sync</code>, and <code>text/template</code>
packages. See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.12.1">Go
1.12.1 milestone</a> on our issue tracker for details.
</p>
<p>
go1.12.2 (released 2019/04/05) includes fixes to the compiler, the go
command, the runtime, and the <code>doc</code>, <code>net</code>,
<code>net/http/httputil</code>, and <code>os</code> packages. See the
<a href="https://github.com/golang/go/issues?q=milestone%3AGo1.12.2">Go
1.12.2 milestone</a> on our issue tracker for details.
</p>
<p>
go1.12.3 (released 2019/04/08) was accidentally released without its
intended fix. It is identical to go1.12.2, except for its version
number. The intended fix is in go1.12.4.
</p>
<p>
go1.12.4 (released 2019/04/11) fixes an issue where using the prebuilt binary
releases on older versions of GNU/Linux
<a href="https://golang.org/issues/31293">led to failures</a>
when linking programs that used cgo.
Only Linux users who hit this issue need to update.
</p>
<p>
go1.12.5 (released 2019/05/06) includes fixes to the compiler, the linker,
the go command, the runtime, and the <code>os</code> package. See the
<a href="https://github.com/golang/go/issues?q=milestone%3AGo1.12.5">Go
1.12.5 milestone</a> on our issue tracker for details.
</p>
<h2 id="go1.11">go1.11 (released 2018/08/24)</h2> <h2 id="go1.11">go1.11 (released 2018/08/24)</h2>
<p> <p>
@ -73,6 +112,48 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.4+labe
1.11.4 milestone</a> on our issue tracker for details. 1.11.4 milestone</a> on our issue tracker for details.
</p> </p>
<p>
go1.11.5 (released 2019/01/23) includes a security fix to the
<code>crypto/elliptic</code> package. See
the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.5">Go
1.11.5 milestone</a> on our issue tracker for details.
</p>
<p>
go1.11.6 (released 2019/03/14) includes fixes to cgo, the compiler, linker,
runtime, go command, and the <code>crypto/x509</code>, <code>encoding/json</code>,
<code>net</code>, and <code>net/url</code> packages. See the
<a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.6">Go
1.11.6 milestone</a> on our issue tracker for details.
</p>
<p>
go1.11.7 (released 2019/04/05) includes fixes to the runtime and the
<code>net</code> packages. See the
<a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.7">Go
1.11.7 milestone</a> on our issue tracker for details.
</p>
<p>
go1.11.8 (released 2019/04/08) was accidentally released without its
intended fix. It is identical to go1.11.7, except for its version
number. The intended fix is in go1.11.9.
</p>
<p>
go1.11.9 (released 2019/04/11) fixes an issue where using the prebuilt binary
releases on older versions of GNU/Linux
<a href="https://golang.org/issues/31293">led to failures</a>
when linking programs that used cgo.
Only Linux users who hit this issue need to update.
</p>
<p>
go1.11.10 (released 2019/05/06) includes fixes to the runtime and the linker.
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.10">Go
1.11.10 milestone</a> on our issue tracker for details.
</p>
<h2 id="go1.10">go1.10 (released 2018/02/16)</h2> <h2 id="go1.10">go1.10 (released 2018/02/16)</h2>
<p> <p>
@ -138,6 +219,13 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.7+labe
Go 1.10.7 milestone</a> on our issue tracker for details. Go 1.10.7 milestone</a> on our issue tracker for details.
</p> </p>
<p>
go1.10.8 (released 2019/01/23) includes a security fix to the
<code>crypto/elliptic</code> package. See
the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.8">Go
1.10.8 milestone</a> on our issue tracker for details.
</p>
<h2 id="go1.9">go1.9 (released 2017/08/24)</h2> <h2 id="go1.9">go1.9 (released 2017/08/24)</h2>
<p> <p>

View file

@ -1680,13 +1680,15 @@ maps. Here is a print statement for the time zone map defined in the previous s
fmt.Printf("%v\n", timeZone) // or just fmt.Println(timeZone) fmt.Printf("%v\n", timeZone) // or just fmt.Println(timeZone)
</pre> </pre>
<p> <p>
which gives output which gives output:
</p> </p>
<pre> <pre>
map[CST:-21600 PST:-28800 EST:-18000 UTC:0 MST:-25200] map[CST:-21600 EST:-18000 MST:-25200 PST:-28800 UTC:0]
</pre> </pre>
<p> <p>
For maps the keys may be output in any order, of course. For maps, <code>Printf</code> and friends sort the output lexicographically by key.
</p>
<p>
When printing a struct, the modified format <code>%+v</code> annotates the When printing a struct, the modified format <code>%+v</code> annotates the
fields of the structure with their names, and for any value the alternate fields of the structure with their names, and for any value the alternate
format <code>%#v</code> prints the value in full Go syntax. format <code>%#v</code> prints the value in full Go syntax.
@ -1710,7 +1712,7 @@ prints
&amp;{7 -2.35 abc def} &amp;{7 -2.35 abc def}
&amp;{a:7 b:-2.35 c:abc def} &amp;{a:7 b:-2.35 c:abc def}
&amp;main.T{a:7, b:-2.35, c:"abc\tdef"} &amp;main.T{a:7, b:-2.35, c:"abc\tdef"}
map[string]int{"CST":-21600, "PST":-28800, "EST":-18000, "UTC":0, "MST":-25200} map[string]int{"CST":-21600, "EST":-18000, "MST":-25200, "PST":-28800, "UTC":0}
</pre> </pre>
<p> <p>
(Note the ampersands.) (Note the ampersands.)

View file

@ -185,6 +185,17 @@ tour
that build fails. that build fails.
</p> </p>
<p><!-- CL 147282, 147281 -->
This changed use of the <code>go</code> directive means that if you
use Go 1.12 to build a module, thus recording <code>go 1.12</code>
in the <code>go.mod</code> file, you will get an error when
attempting to build the same module with Go 1.11 through Go 1.11.3.
Go 1.11.4 or later will work fine, as will releases older than Go 1.11.
If you must use Go 1.11 through 1.11.3, you can avoid the problem by
setting the language version to 1.11, using the Go 1.12 go tool,
via <code>go mod edit -go=1.11</code>.
</p>
<p><!-- CL 152739 --> <p><!-- CL 152739 -->
When an import cannot be resolved using the active modules, When an import cannot be resolved using the active modules,
the <code>go</code> command will now try to use the modules mentioned in the the <code>go</code> command will now try to use the modules mentioned in the
@ -600,17 +611,6 @@ for {
</dl><!-- io --> </dl><!-- io -->
<dl id="lib/time"><dt><a href="/pkg/lib/time/">lib/time</a></dt>
<dd>
<p><!-- CL 151299 -->
The time zone database in <code>$GOROOT/lib/time/zoneinfo.zip</code>
has been updated to version 2018i. Note that this ZIP file is
only used if a time zone database is not provided by the operating
system.
</p>
</dl><!-- lib/time -->
<dl id="math"><dt><a href="/pkg/math/">math</a></dt> <dl id="math"><dt><a href="/pkg/math/">math</a></dt>
<dd> <dd>
<p><!-- CL 153059 --> <p><!-- CL 153059 -->
@ -791,7 +791,7 @@ for {
A new <a href="/pkg/runtime/debug/#BuildInfo"><code>BuildInfo</code></a> type A new <a href="/pkg/runtime/debug/#BuildInfo"><code>BuildInfo</code></a> type
exposes the build information read from the running binary, available only in exposes the build information read from the running binary, available only in
binaries built with module support. This includes the main package path, main binaries built with module support. This includes the main package path, main
module information, and the module dependencies. This type is given though the module information, and the module dependencies. This type is given through the
<a href="/pkg/runtime/debug/#ReadBuildInfo"><code>ReadBuildInfo</code></a> function <a href="/pkg/runtime/debug/#ReadBuildInfo"><code>ReadBuildInfo</code></a> function
on <a href="/pkg/runtime/debug/#BuildInfo"><code>BuildInfo</code></a>. on <a href="/pkg/runtime/debug/#BuildInfo"><code>BuildInfo</code></a>.
</p> </p>
@ -924,6 +924,17 @@ for {
</p> </p>
</dl><!-- text/template --> </dl><!-- text/template -->
<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
<dd>
<p><!-- CL 151299 -->
The time zone database in <code>$GOROOT/lib/time/zoneinfo.zip</code>
has been updated to version 2018i. Note that this ZIP file is
only used if a time zone database is not provided by the operating
system.
</p>
</dl><!-- time -->
<dl id="unsafe"><dt><a href="/pkg/unsafe/">unsafe</a></dt> <dl id="unsafe"><dt><a href="/pkg/unsafe/">unsafe</a></dt>
<dd> <dd>
<p><!-- CL 146058 --> <p><!-- CL 146058 -->

97
doc/go1.13.html Normal file
View file

@ -0,0 +1,97 @@
<!--{
"Title": "Go 1.13 Release Notes",
"Path": "/doc/go1.13",
"Template": true
}-->
<!--
NOTE: In this document and others in this directory, the convention is to
set fixed-width phrases with non-fixed-width spaces, as in
<code>hello</code> <code>world</code>.
Do not send CLs removing the interior tags from such phrases.
-->
<style>
ul li { margin: 0.5em 0; }
</style>
<h2 id="introduction">DRAFT RELEASE NOTES - Introduction to Go 1.13</h2>
<p>
<strong>
Go 1.13 is not yet released. These are work-in-progress
release notes. Go 1.13 is expected to be released in August 2019.
</strong>
</p>
<p>
TODO
</p>
<h2 id="language">Changes to the language</h2>
<p>
TODO
</p>
<h2 id="ports">Ports</h2>
<p>
TODO
</p>
<h3 id="darwin">Darwin</h3>
<p>
As <a href="go1.12#darwin">announced</a> in the Go 1.12 release notes,
Go 1.13 now requires macOS 10.11 El Capitan or later;
support for previous versions has been discontinued.
</p>
<h3 id="freebsd">FreeBSD</h3>
<p>
As <a href="go1.12#freebsd">announced</a> in the Go 1.12 release notes,
Go 1.13 now requires FreeBSD 11.2 or later;
support for previous versions has been discontinued.
FreeBSD 12.0 or later requires a kernel with the COMPAT_FREEBSD11 option set (this is the default).
</p>
<h2 id="tools">Tools</h2>
<p>
TODO
</p>
<h2 id="runtime">Runtime</h2>
<p>
TODO
</p>
<h2 id="library">Core library</h2>
<p>
TODO generally
</p>
<h3 id="tls_1_3">TLS 1.3</h3>
<p>
TODO; link to <a href="/doc/go1.12#tls_1_3">Go 1.12 notes</a>.
</p>
<h3 id="minor_library_changes">Minor changes to the library</h3>
<p>
As always, there are various minor changes and updates to the library,
made with the Go 1 <a href="/doc/go1compat">promise of compatibility</a>
in mind.
</p>
<p>
TODO
</p>

View file

@ -2082,8 +2082,8 @@ At the beginning of the project we considered using LLVM for
our performance goals. our performance goals.
More important in retrospect, starting with LLVM would have made it More important in retrospect, starting with LLVM would have made it
harder to introduce some of the ABI and related changes, such as harder to introduce some of the ABI and related changes, such as
stack management, that Go requires but not are not part of the stack management, that Go requires but are not part of the standard
standard C setup. C setup.
A new <a href="https://go.googlesource.com/gollvm/">LLVM implementation</a> A new <a href="https://go.googlesource.com/gollvm/">LLVM implementation</a>
is starting to come together now, however. is starting to come together now, however.
</p> </p>

View file

@ -1,6 +1,6 @@
<!--{ <!--{
"Title": "The Go Programming Language Specification", "Title": "The Go Programming Language Specification",
"Subtitle": "Version of February 16, 2019", "Subtitle": "Version of May 14, 2019",
"Path": "/ref/spec" "Path": "/ref/spec"
}--> }-->
@ -118,6 +118,7 @@ The underscore character <code>_</code> (U+005F) is considered a letter.
<pre class="ebnf"> <pre class="ebnf">
letter = unicode_letter | "_" . letter = unicode_letter | "_" .
decimal_digit = "0" … "9" . decimal_digit = "0" … "9" .
binary_digit = "0" | "1" .
octal_digit = "0" … "7" . octal_digit = "0" … "7" .
hex_digit = "0" … "9" | "A" … "F" | "a" … "f" . hex_digit = "0" … "9" | "A" … "F" | "a" … "f" .
</pre> </pre>
@ -273,71 +274,156 @@ The following character sequences represent <a href="#Operators">operators</a>
<p> <p>
An integer literal is a sequence of digits representing an An integer literal is a sequence of digits representing an
<a href="#Constants">integer constant</a>. <a href="#Constants">integer constant</a>.
An optional prefix sets a non-decimal base: <code>0</code> for octal, <code>0x</code> or An optional prefix sets a non-decimal base: <code>0b</code> or <code>0B</code>
<code>0X</code> for hexadecimal. In hexadecimal literals, letters for binary, <code>0</code>, <code>0o</code>, or <code>0O</code> for octal,
<code>a-f</code> and <code>A-F</code> represent values 10 through 15. and <code>0x</code> or <code>0X</code> for hexadecimal.
A single <code>0</code> is considered a decimal zero.
In hexadecimal literals, letters <code>a</code> through <code>f</code>
and <code>A</code> through <code>F</code> represent values 10 through 15.
</p>
<p>
For readability, an underscore character <code>_</code> may appear after
a base prefix or between successive digits; such underscores do not change
the literal's value.
</p> </p>
<pre class="ebnf"> <pre class="ebnf">
int_lit = decimal_lit | octal_lit | hex_lit . int_lit = decimal_lit | binary_lit | octal_lit | hex_lit .
decimal_lit = ( "1" … "9" ) { decimal_digit } . decimal_lit = "0" | ( "1" … "9" ) [ [ "_" ] decimal_digits ] .
octal_lit = "0" { octal_digit } . binary_lit = "0" ( "b" | "B" ) [ "_" ] binary_digits .
hex_lit = "0" ( "x" | "X" ) hex_digit { hex_digit } . octal_lit = "0" [ "o" | "O" ] [ "_" ] octal_digits .
hex_lit = "0" ( "x" | "X" ) [ "_" ] hex_digits .
decimal_digits = decimal_digit { [ "_" ] decimal_digit } .
binary_digits = binary_digit { [ "_" ] binary_digit } .
octal_digits = octal_digit { [ "_" ] octal_digit } .
hex_digits = hex_digit { [ "_" ] hex_digit } .
</pre> </pre>
<pre> <pre>
42 42
4_2
0600 0600
0_600
0o600
0O600 // second character is capital letter 'O'
0xBadFace 0xBadFace
0xBad_Face
0x_67_7a_2f_cc_40_c6
170141183460469231731687303715884105727 170141183460469231731687303715884105727
170_141183_460469_231731_687303_715884_105727
_42 // an identifier, not an integer literal
42_ // invalid: _ must separate successive digits
4__2 // invalid: only one _ at a time
0_xBadFace // invalid: _ must separate successive digits
</pre> </pre>
<h3 id="Floating-point_literals">Floating-point literals</h3> <h3 id="Floating-point_literals">Floating-point literals</h3>
<p> <p>
A floating-point literal is a decimal representation of a A floating-point literal is a decimal or hexadecimal representation of a
<a href="#Constants">floating-point constant</a>. <a href="#Constants">floating-point constant</a>.
It has an integer part, a decimal point, a fractional part,
and an exponent part. The integer and fractional part comprise
decimal digits; the exponent part is an <code>e</code> or <code>E</code>
followed by an optionally signed decimal exponent. One of the
integer part or the fractional part may be elided; one of the decimal
point or the exponent may be elided.
</p> </p>
<p>
A decimal floating-point literal consists of an integer part (decimal digits),
a decimal point, a fractional part (decimal digits), and an exponent part
(<code>e</code> or <code>E</code> followed by an optional sign and decimal digits).
One of the integer part or the fractional part may be elided; one of the decimal point
or the exponent part may be elided.
An exponent value exp scales the mantissa (integer and fractional part) by 10<sup>exp</sup>.
</p>
<p>
A hexadecimal floating-point literal consists of a <code>0x</code> or <code>0X</code>
prefix, an integer part (hexadecimal digits), a radix point, a fractional part (hexadecimal digits),
and an exponent part (<code>p</code> or <code>P</code> followed by an optional sign and decimal digits).
One of the integer part or the fractional part may be elided; the radix point may be elided as well,
but the exponent part is required. (This syntax matches the one given in IEEE 754-2008 §5.12.3.)
An exponent value exp scales the mantissa (integer and fractional part) by 2<sup>exp</sup>.
</p>
<p>
For readability, an underscore character <code>_</code> may appear after
a base prefix or between successive digits; such underscores do not change
the literal value.
</p>
<pre class="ebnf"> <pre class="ebnf">
float_lit = decimals "." [ decimals ] [ exponent ] | float_lit = decimal_float_lit | hex_float_lit .
decimals exponent |
"." decimals [ exponent ] . decimal_float_lit = decimal_digits "." [ decimal_digits ] [ decimal_exponent ] |
decimals = decimal_digit { decimal_digit } . decimal_digits decimal_exponent |
exponent = ( "e" | "E" ) [ "+" | "-" ] decimals . "." decimal_digits [ decimal_exponent ] .
decimal_exponent = ( "e" | "E" ) [ "+" | "-" ] decimal_digits .
hex_float_lit = "0" ( "x" | "X" ) hex_mantissa hex_exponent .
hex_mantissa = [ "_" ] hex_digits "." [ hex_digits ] |
[ "_" ] hex_digits |
"." hex_digits .
hex_exponent = ( "p" | "P" ) [ "+" | "-" ] decimal_digits .
</pre> </pre>
<pre> <pre>
0. 0.
72.40 72.40
072.40 // == 72.40 072.40 // == 72.40
2.71828 2.71828
1.e+0 1.e+0
6.67428e-11 6.67428e-11
1E6 1E6
.25 .25
.12345E+5 .12345E+5
1_5. // == 15.0
0.15e+0_2 // == 15.0
0x1p-2 // == 0.25
0x2.p10 // == 2048.0
0x1.Fp+0 // == 1.9375
0X.8p-0 // == 0.5
0X_1FFFP-16 // == 0.1249847412109375
0x15e-2 // == 0x15e - 2 (integer subtraction)
0x.p1 // invalid: mantissa has no digits
1p-2 // invalid: p exponent requires hexadecimal mantissa
0x1.5e-2 // invalid: hexadecimal mantissa requires p exponent
1_.5 // invalid: _ must separate successive digits
1._5 // invalid: _ must separate successive digits
1.5_e1 // invalid: _ must separate successive digits
1.5e_1 // invalid: _ must separate successive digits
1.5e1_ // invalid: _ must separate successive digits
</pre> </pre>
<h3 id="Imaginary_literals">Imaginary literals</h3> <h3 id="Imaginary_literals">Imaginary literals</h3>
<p> <p>
An imaginary literal is a decimal representation of the imaginary part of a An imaginary literal represents the imaginary part of a
<a href="#Constants">complex constant</a>. <a href="#Constants">complex constant</a>.
It consists of a It consists of an <a href="#Integer_literals">integer</a> or
<a href="#Floating-point_literals">floating-point literal</a> <a href="#Floating-point_literals">floating-point</a> literal
or decimal integer followed followed by the lower-case letter <code>i</code>.
by the lower-case letter <code>i</code>. The value of an imaginary literal is the value of the respective
integer or floating-point literal multiplied by the imaginary unit <i>i</i>.
</p> </p>
<pre class="ebnf"> <pre class="ebnf">
imaginary_lit = (decimals | float_lit) "i" . imaginary_lit = (decimal_digits | int_lit | float_lit) "i" .
</pre> </pre>
<p>
For backward compatibility, an imaginary literal's integer part consisting
entirely of decimal digits (and possibly underscores) is considered a decimal
integer, even if it starts with a leading <code>0</code>.
</p>
<pre> <pre>
0i 0i
011i // == 11i 0123i // == 123i for backward-compatibility
0o123i // == 0o123 * 1i == 83i
0xabci // == 0xabc * 1i == 2748i
0.i 0.i
2.71828i 2.71828i
1.e+0i 1.e+0i
@ -345,6 +431,7 @@ imaginary_lit = (decimals | float_lit) "i" .
1E6i 1E6i
.25i .25i
.12345E+5i .12345E+5i
0x1p-2i // == 0x1p-2 * 1i == 0.25i
</pre> </pre>
@ -361,6 +448,7 @@ of the character itself,
while multi-character sequences beginning with a backslash encode while multi-character sequences beginning with a backslash encode
values in various formats. values in various formats.
</p> </p>
<p> <p>
The simplest form represents the single character within the quotes; The simplest form represents the single character within the quotes;
since Go source text is Unicode characters encoded in UTF-8, multiple since Go source text is Unicode characters encoded in UTF-8, multiple
@ -370,6 +458,7 @@ a literal <code>a</code>, Unicode U+0061, value <code>0x61</code>, while
<code>'ä'</code> holds two bytes (<code>0xc3</code> <code>0xa4</code>) representing <code>'ä'</code> holds two bytes (<code>0xc3</code> <code>0xa4</code>) representing
a literal <code>a</code>-dieresis, U+00E4, value <code>0xe4</code>. a literal <code>a</code>-dieresis, U+00E4, value <code>0xe4</code>.
</p> </p>
<p> <p>
Several backslash escapes allow arbitrary values to be encoded as Several backslash escapes allow arbitrary values to be encoded as
ASCII text. There are four ways to represent the integer value ASCII text. There are four ways to represent the integer value
@ -380,6 +469,7 @@ plain backslash <code>\</code> followed by exactly three octal digits.
In each case the value of the literal is the value represented by In each case the value of the literal is the value represented by
the digits in the corresponding base. the digits in the corresponding base.
</p> </p>
<p> <p>
Although these representations all result in an integer, they have Although these representations all result in an integer, they have
different valid ranges. Octal escapes must represent a value between different valid ranges. Octal escapes must represent a value between
@ -388,9 +478,11 @@ by construction. The escapes <code>\u</code> and <code>\U</code>
represent Unicode code points so within them some values are illegal, represent Unicode code points so within them some values are illegal,
in particular those above <code>0x10FFFF</code> and surrogate halves. in particular those above <code>0x10FFFF</code> and surrogate halves.
</p> </p>
<p> <p>
After a backslash, certain single-character escapes represent special values: After a backslash, certain single-character escapes represent special values:
</p> </p>
<pre class="grammar"> <pre class="grammar">
\a U+0007 alert or bell \a U+0007 alert or bell
\b U+0008 backspace \b U+0008 backspace
@ -403,6 +495,7 @@ After a backslash, certain single-character escapes represent special values:
\' U+0027 single quote (valid escape only within rune literals) \' U+0027 single quote (valid escape only within rune literals)
\" U+0022 double quote (valid escape only within string literals) \" U+0022 double quote (valid escape only within string literals)
</pre> </pre>
<p> <p>
All other sequences starting with a backslash are illegal inside rune literals. All other sequences starting with a backslash are illegal inside rune literals.
</p> </p>
@ -446,6 +539,7 @@ A string literal represents a <a href="#Constants">string constant</a>
obtained from concatenating a sequence of characters. There are two forms: obtained from concatenating a sequence of characters. There are two forms:
raw string literals and interpreted string literals. raw string literals and interpreted string literals.
</p> </p>
<p> <p>
Raw string literals are character sequences between back quotes, as in Raw string literals are character sequences between back quotes, as in
<code>`foo`</code>. Within the quotes, any character may appear except <code>`foo`</code>. Within the quotes, any character may appear except
@ -457,6 +551,7 @@ contain newlines.
Carriage return characters ('\r') inside raw string literals Carriage return characters ('\r') inside raw string literals
are discarded from the raw string value. are discarded from the raw string value.
</p> </p>
<p> <p>
Interpreted string literals are character sequences between double Interpreted string literals are character sequences between double
quotes, as in <code>&quot;bar&quot;</code>. quotes, as in <code>&quot;bar&quot;</code>.
@ -596,6 +691,7 @@ precision in the language, a compiler may implement them using an
internal representation with limited precision. That said, every internal representation with limited precision. That said, every
implementation must: implementation must:
</p> </p>
<ul> <ul>
<li>Represent integer constants with at least 256 bits.</li> <li>Represent integer constants with at least 256 bits.</li>
@ -613,12 +709,14 @@ implementation must:
represent a floating-point or complex constant due to limits represent a floating-point or complex constant due to limits
on precision.</li> on precision.</li>
</ul> </ul>
<p> <p>
These requirements apply both to literal constants and to the result These requirements apply both to literal constants and to the result
of evaluating <a href="#Constant_expressions">constant of evaluating <a href="#Constant_expressions">constant
expressions</a>. expressions</a>.
</p> </p>
<h2 id="Variables">Variables</h2> <h2 id="Variables">Variables</h2>
<p> <p>
@ -2415,10 +2513,24 @@ For array and slice literals the following rules apply:
generates a pointer to a unique <a href="#Variables">variable</a> initialized generates a pointer to a unique <a href="#Variables">variable</a> initialized
with the literal's value. with the literal's value.
</p> </p>
<pre> <pre>
var pointer *Point3D = &amp;Point3D{y: 1000} var pointer *Point3D = &amp;Point3D{y: 1000}
</pre> </pre>
<p>
Note that the <a href="#The_zero_value">zero value</a> for a slice or map
type is not the same as an initialized but empty value of the same type.
Consequently, taking the address of an empty slice or map composite literal
does not have the same effect as allocating a new slice or map value with
<a href="#Allocation">new</a>.
</p>
<pre>
p1 := &[]int{} // p1 points to an initialized, empty slice with value []int{} and length 0
p2 := new([]int) // p2 points to an uninitialized slice with value nil and length 0
</pre>
<p> <p>
The length of an array literal is the length specified in the literal type. The length of an array literal is the length specified in the literal type.
If fewer elements than the length are provided in the literal, the missing If fewer elements than the length are provided in the literal, the missing
@ -3150,6 +3262,14 @@ is a <code>nil</code> slice. Otherwise, if the result is a slice, it shares its
array with the operand. array with the operand.
</p> </p>
<pre>
var a [10]int
s1 := a[3:7] // underlying array of s1 is array a; &s1[2] == &a[5]
s2 := s1[1:4] // underlying array of s2 is underlying array of s1 which is array a; &s2[1] == &a[5]
s2[1] = 42 // s2[1] == s1[2] == a[5] == 42; they all refer to the same underlying array element
</pre>
<h4>Full slice expressions</h4> <h4>Full slice expressions</h4>
<p> <p>
@ -3386,7 +3506,7 @@ within <code>Greeting</code>, <code>who</code> will have the value
</p> </p>
<p> <p>
If the final argument is assignable to a slice type <code>[]T</code>, it may be If the final argument is assignable to a slice type <code>[]T</code>, it is
passed unchanged as the value for a <code>...T</code> parameter if the argument passed unchanged as the value for a <code>...T</code> parameter if the argument
is followed by <code>...</code>. In this case no new slice is created. is followed by <code>...</code>. In this case no new slice is created.
</p> </p>
@ -6264,16 +6384,16 @@ var t T
<h3 id="Package_initialization">Package initialization</h3> <h3 id="Package_initialization">Package initialization</h3>
<p> <p>
Within a package, package-level variables are initialized in Within a package, package-level variable initialization proceeds stepwise,
<i>declaration order</i> but after any of the variables with each step selecting the variable earliest in <i>declaration order</i>
they <i>depend</i> on. which has no dependencies on uninitialized variables.
</p> </p>
<p> <p>
More precisely, a package-level variable is considered <i>ready for More precisely, a package-level variable is considered <i>ready for
initialization</i> if it is not yet initialized and either has initialization</i> if it is not yet initialized and either has
no <a href="#Variable_declarations">initialization expression</a> or no <a href="#Variable_declarations">initialization expression</a> or
its initialization expression has no dependencies on uninitialized variables. its initialization expression has no <i>dependencies</i> on uninitialized variables.
Initialization proceeds by repeatedly initializing the next package-level Initialization proceeds by repeatedly initializing the next package-level
variable that is earliest in declaration order and ready for initialization, variable that is earliest in declaration order and ready for initialization,
until there are no variables ready for initialization. until there are no variables ready for initialization.
@ -6285,6 +6405,23 @@ process ends, those variables are part of one or more initialization cycles,
and the program is not valid. and the program is not valid.
</p> </p>
<p>
Multiple variables on the left-hand side of a variable declaration initialized
by single (multi-valued) expression on the right-hand side are initialized
together: If any of the variables on the left-hand side is initialized, all
those variables are initialized in the same step.
</p>
<pre>
var x = a
var a, b = f() // a and b are initialized together, before x is initialized
</pre>
<p>
For the purpose of package initialization, <a href="#Blank_identifier">blank</a>
variables are treated like any other variables in declarations.
</p>
<p> <p>
The declaration order of variables declared in multiple files is determined The declaration order of variables declared in multiple files is determined
by the order in which the files are presented to the compiler: Variables by the order in which the files are presented to the compiler: Variables
@ -6326,22 +6463,16 @@ or to a function or method that depends on <code>y</code>.
</li> </li>
</ul> </ul>
<p>
Dependency analysis is performed per package; only references referring
to variables, functions, and methods declared in the current package
are considered.
</p>
<p> <p>
For example, given the declarations For example, given the declarations
</p> </p>
<pre> <pre>
var ( var (
a = c + b a = c + b // == 9
b = f() b = f() // == 4
c = f() c = f() // == 5
d = 3 d = 3 // == 5 after initialization has finished
) )
func f() int { func f() int {
@ -6352,6 +6483,39 @@ func f() int {
<p> <p>
the initialization order is <code>d</code>, <code>b</code>, <code>c</code>, <code>a</code>. the initialization order is <code>d</code>, <code>b</code>, <code>c</code>, <code>a</code>.
Note that the order of subexpressions in initialization expressions is irrelevant:
<code>a = c + b</code> and <code>a = b + c</code> result in the same initialization
order in this example.
</p>
<p>
Dependency analysis is performed per package; only references referring
to variables, functions, and (non-interface) methods declared in the current
package are considered. If other, hidden, data dependencies exists between
variables, the initialization order between those variables is unspecified.
</p>
<p>
For instance, given the declarations
</p>
<pre>
var x = I(T{}).ab() // x has an undetected, hidden dependency on a and b
var _ = sideEffect() // unrelated to x, a, or b
var a = b
var b = 42
type I interface { ab() []int }
type T struct{}
func (T) ab() []int { return []int{a, b} }
</pre>
<p>
the variable <code>a</code> will be initialized after <code>b</code> but
whether <code>x</code> is initialized before <code>b</code>, between
<code>b</code> and <code>a</code>, or after <code>a</code>, and
thus also the moment at which <code>sideEffect()</code> is called (before
or after <code>x</code> is initialized) is not specified.
</p> </p>
<p> <p>

View file

@ -627,6 +627,29 @@ contains further details regarding Go's ARM support.
</p> </p>
</li> </li>
<li><code>$GOPPC64</code> (for <code>ppc64</code> and <code>ppc64le</code> only)
<p>
This variable sets the processor level (i.e. Instruction Set Architecture version)
for which the compiler will target. The default is <code>power8</code>.
</p>
<ul>
<li><code>GOPPC64=power8</code>: generate ISA v2.07 instructions</li>
<li><code>GOPPC64=power9</code>: generate ISA v3.00 instructions</li>
</ul>
</li>
<li><code>$GOWASM</code> (for <code>wasm</code> only)
<p>
This variable is a comma separated list of <a href="https://github.com/WebAssembly/proposals">experimental WebAssembly features</a> that the compiled WebAssembly binary is allowed to use.
The default is to use no experimental features.
</p>
<ul>
<li><code>GOWASM=satconv</code>: generate <a href="https://github.com/WebAssembly/nontrapping-float-to-int-conversions/blob/master/proposals/nontrapping-float-to-int-conversion/Overview.md">saturating (non-trapping) float-to-int conversions</a></li>
<li><code>GOWASM=signext</code>: generate <a href="https://github.com/WebAssembly/sign-extension-ops/blob/master/proposals/sign-extension-ops/Overview.md">sign-extension operators</a></li>
</ul>
</li>
</ul> </ul>
<p> <p>

View file

@ -50,7 +50,7 @@ If your OS or architecture is not on the list, you may be able to
<tr><td>FreeBSD 10.3 or later</td> <td>amd64, 386</td> <td>Debian GNU/kFreeBSD not supported</td></tr> <tr><td>FreeBSD 10.3 or later</td> <td>amd64, 386</td> <td>Debian GNU/kFreeBSD not supported</td></tr>
<tr valign='top'><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm, arm64,<br>s390x, ppc64le</td> <td>CentOS/RHEL 5.x not supported.<br>Install from source for other libc.</td></tr> <tr valign='top'><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm, arm64,<br>s390x, ppc64le</td> <td>CentOS/RHEL 5.x not supported.<br>Install from source for other libc.</td></tr>
<tr><td>macOS 10.10 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>&#8224;</sup> that comes with Xcode<sup>&#8225;</sup> for <code>cgo</code> support</td></tr> <tr><td>macOS 10.10 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>&#8224;</sup> that comes with Xcode<sup>&#8225;</sup> for <code>cgo</code> support</td></tr>
<tr><td>Windows 7, Server 2008R2 or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>&#8224;</sup>. No need for cygwin or msys.</td></tr> <tr valign='top'><td>Windows 7, Server 2008R2 or later</td> <td>amd64, 386</td> <td>use MinGW (<code>386</code>) or MinGW-W64 (<code>amd64</code>) gcc<sup>&#8224;</sup>.<br>No need for cygwin or msys.</td></tr>
</table> </table>
<p> <p>
@ -204,7 +204,7 @@ you will need to <a href="https://golang.org/wiki/SettingGOPATH">set the <code>G
</p> </p>
<p> <p>
Next, make the directory <code>src/hello</code> inside your workspace, Next, make the directory <code class="testUnix">src/hello</code><code class="testWindows">src\hello</code> inside your workspace,
and in that directory create a file named <code>hello.go</code> that looks like: and in that directory create a file named <code>hello.go</code> that looks like:
</p> </p>

View file

@ -12,7 +12,7 @@ C compiler from the Android NDK. For example,
CGO_ENABLED=1 \ CGO_ENABLED=1 \
GOOS=android \ GOOS=android \
GOARCH=arm64 \ GOARCH=arm64 \
CC=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang \ CC_FOR_TARGET=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang \
./all.bash ./all.bash
To run tests on the Android device, add the bin directory to PATH so the To run tests on the Android device, add the bin directory to PATH so the

View file

@ -10,6 +10,7 @@ package main
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"go/build" "go/build"
"io" "io"
@ -25,12 +26,9 @@ import (
"syscall" "syscall"
) )
func run(args ...string) string { func run(args ...string) (string, error) {
if flags := os.Getenv("GOANDROID_ADB_FLAGS"); flags != "" { cmd := adbCmd(args...)
args = append(strings.Split(flags, " "), args...)
}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
cmd := exec.Command("adb", args...)
cmd.Stdout = io.MultiWriter(os.Stdout, buf) cmd.Stdout = io.MultiWriter(os.Stdout, buf)
// If the adb subprocess somehow hangs, go test will kill this wrapper // If the adb subprocess somehow hangs, go test will kill this wrapper
// and wait for our os.Stderr (and os.Stdout) to close as a result. // and wait for our os.Stderr (and os.Stdout) to close as a result.
@ -42,69 +40,113 @@ func run(args ...string) string {
// forcing cmd.Run to use another pipe and goroutine to pass // forcing cmd.Run to use another pipe and goroutine to pass
// along stderr from adb. // along stderr from adb.
cmd.Stderr = struct{ io.Writer }{os.Stderr} cmd.Stderr = struct{ io.Writer }{os.Stderr}
log.Printf("adb %s", strings.Join(args, " "))
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
log.Fatalf("adb %s: %v", strings.Join(args, " "), err) return "", fmt.Errorf("adb %s: %v", strings.Join(args, " "), err)
} }
return buf.String() return buf.String(), nil
}
func adb(args ...string) error {
if out, err := adbCmd(args...).CombinedOutput(); err != nil {
fmt.Fprintf(os.Stderr, "adb %s\n%s", strings.Join(args, " "), out)
return err
}
return nil
}
func adbCmd(args ...string) *exec.Cmd {
if flags := os.Getenv("GOANDROID_ADB_FLAGS"); flags != "" {
args = append(strings.Split(flags, " "), args...)
}
return exec.Command("adb", args...)
} }
const ( const (
// Directory structure on the target device androidtest.bash assumes. deviceRoot = "/data/local/tmp/go_android_exec"
deviceGoroot = "/data/local/tmp/goroot" deviceGoroot = deviceRoot + "/goroot"
deviceGopath = "/data/local/tmp/gopath"
) )
func main() { func main() {
log.SetFlags(0) log.SetFlags(0)
log.SetPrefix("go_android_exec: ") log.SetPrefix("go_android_exec: ")
exitCode, err := runMain()
if err != nil {
log.Fatal(err)
}
os.Exit(exitCode)
}
func runMain() (int, error) {
// Concurrent use of adb is flaky, so serialize adb commands. // Concurrent use of adb is flaky, so serialize adb commands.
// See https://github.com/golang/go/issues/23795 or // See https://github.com/golang/go/issues/23795 or
// https://issuetracker.google.com/issues/73230216. // https://issuetracker.google.com/issues/73230216.
lockPath := filepath.Join(os.TempDir(), "go_android_exec-adb-lock") lockPath := filepath.Join(os.TempDir(), "go_android_exec-adb-lock")
lock, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0666) lock, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil { if err != nil {
log.Fatal(err) return 0, err
} }
defer lock.Close() defer lock.Close()
if err := syscall.Flock(int(lock.Fd()), syscall.LOCK_EX); err != nil { if err := syscall.Flock(int(lock.Fd()), syscall.LOCK_EX); err != nil {
log.Fatal(err) return 0, err
} }
// In case we're booting a device or emulator alongside androidtest.bash // In case we're booting a device or emulator alongside all.bash, wait for
// wait for it to be ready. adb wait-for-device is not enough, we have to // it to be ready. adb wait-for-device is not enough, we have to
// wait for sys.boot_completed. // wait for sys.boot_completed.
run("wait-for-device", "shell", "while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;") if err := adb("wait-for-device", "exec-out", "while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;"); err != nil {
return 0, err
}
// Done once per make.bash.
if err := adbCopyGoroot(); err != nil {
return 0, err
}
// Prepare a temporary directory that will be cleaned up at the end. // Prepare a temporary directory that will be cleaned up at the end.
deviceGotmp := fmt.Sprintf("/data/local/tmp/%s-%d", // Binary names can conflict.
filepath.Base(os.Args[1]), os.Getpid()) // E.g. template.test from the {html,text}/template packages.
run("shell", "mkdir", "-p", deviceGotmp) binName := filepath.Base(os.Args[1])
deviceGotmp := fmt.Sprintf(deviceRoot+"/%s-%d", binName, os.Getpid())
deviceGopath := deviceGotmp + "/gopath"
defer adb("exec-out", "rm", "-rf", deviceGotmp) // Clean up.
// Determine the package by examining the current working // Determine the package by examining the current working
// directory, which will look something like // directory, which will look something like
// "$GOROOT/src/mime/multipart" or "$GOPATH/src/golang.org/x/mobile". // "$GOROOT/src/mime/multipart" or "$GOPATH/src/golang.org/x/mobile".
// We extract everything after the $GOROOT or $GOPATH to run on the // We extract everything after the $GOROOT or $GOPATH to run on the
// same relative directory on the target device. // same relative directory on the target device.
subdir, inGoRoot := subdir() subdir, inGoRoot, err := subdir()
deviceCwd := filepath.Join(deviceGoroot, subdir) if err != nil {
if !inGoRoot { return 0, err
deviceCwd = filepath.Join(deviceGopath, subdir) }
} else { deviceCwd := filepath.Join(deviceGopath, subdir)
adbSyncGoroot() if inGoRoot {
deviceCwd = filepath.Join(deviceGoroot, subdir)
} else {
if err := adb("exec-out", "mkdir", "-p", deviceCwd); err != nil {
return 0, err
}
if err := adbCopyTree(deviceCwd, subdir); err != nil {
return 0, err
}
// Copy .go files from the package.
goFiles, err := filepath.Glob("*.go")
if err != nil {
return 0, err
}
if len(goFiles) > 0 {
args := append(append([]string{"push"}, goFiles...), deviceCwd)
if err := adb(args...); err != nil {
return 0, err
}
}
} }
run("shell", "mkdir", "-p", deviceCwd)
// Binary names can conflict.
// E.g. template.test from the {html,text}/template packages.
binName := fmt.Sprintf("%s-%d", filepath.Base(os.Args[1]), os.Getpid())
deviceBin := fmt.Sprintf("%s/%s", deviceGotmp, binName) deviceBin := fmt.Sprintf("%s/%s", deviceGotmp, binName)
run("push", os.Args[1], deviceBin) if err := adb("push", os.Args[1], deviceBin); err != nil {
return 0, err
if _, err := os.Stat("testdata"); err == nil {
run("push", "testdata", deviceCwd)
} }
// Forward SIGQUIT from the go command to show backtraces from // Forward SIGQUIT from the go command to show backtraces from
@ -115,108 +157,185 @@ func main() {
for range quit { for range quit {
// We don't have the PID of the running process; use the // We don't have the PID of the running process; use the
// binary name instead. // binary name instead.
run("shell", "killall -QUIT "+binName) adb("exec-out", "killall -QUIT "+binName)
} }
}() }()
// The adb shell command will return an exit code of 0 regardless // In light of
// of the command run. E.g.
// $ adb shell false
// $ echo $?
// 0
// https://code.google.com/p/android/issues/detail?id=3254 // https://code.google.com/p/android/issues/detail?id=3254
// So we append the exitcode to the output and parse it from there. // dont trust the exitcode of adb. Instead, append the exitcode to
// the output and parse it from there.
const exitstr = "exitcode=" const exitstr = "exitcode="
cmd := `export TMPDIR="` + deviceGotmp + `"` + cmd := `export TMPDIR="` + deviceGotmp + `"` +
`; export GOROOT="` + deviceGoroot + `"` + `; export GOROOT="` + deviceGoroot + `"` +
`; export GOPATH="` + deviceGopath + `"` + `; export GOPATH="` + deviceGopath + `"` +
`; export CGO_ENABLED=0` +
`; export GOPROXY=` + os.Getenv("GOPROXY") +
`; export GOCACHE="` + deviceRoot + `/gocache"` +
`; export PATH=$PATH:"` + deviceGoroot + `/bin"` +
`; cd "` + deviceCwd + `"` + `; cd "` + deviceCwd + `"` +
"; '" + deviceBin + "' " + strings.Join(os.Args[2:], " ") + "; '" + deviceBin + "' " + strings.Join(os.Args[2:], " ") +
"; echo -n " + exitstr + "$?" "; echo -n " + exitstr + "$?"
output := run("shell", cmd) output, err := run("exec-out", cmd)
signal.Reset(syscall.SIGQUIT) signal.Reset(syscall.SIGQUIT)
close(quit) close(quit)
if err != nil {
run("shell", "rm", "-rf", deviceGotmp) // Clean up. return 0, err
}
exitIdx := strings.LastIndex(output, exitstr) exitIdx := strings.LastIndex(output, exitstr)
if exitIdx == -1 { if exitIdx == -1 {
log.Fatalf("no exit code: %q", output) return 0, fmt.Errorf("no exit code: %q", output)
} }
code, err := strconv.Atoi(output[exitIdx+len(exitstr):]) code, err := strconv.Atoi(output[exitIdx+len(exitstr):])
if err != nil { if err != nil {
log.Fatalf("bad exit code: %v", err) return 0, fmt.Errorf("bad exit code: %v", err)
} }
os.Exit(code) return code, nil
} }
// subdir determines the package based on the current working directory, // subdir determines the package based on the current working directory,
// and returns the path to the package source relative to $GOROOT (or $GOPATH). // and returns the path to the package source relative to $GOROOT (or $GOPATH).
func subdir() (pkgpath string, underGoRoot bool) { func subdir() (pkgpath string, underGoRoot bool, err error) {
cwd, err := os.Getwd() cwd, err := os.Getwd()
if err != nil { if err != nil {
log.Fatal(err) return "", false, err
} }
if root := runtime.GOROOT(); strings.HasPrefix(cwd, root) { cwd, err = filepath.EvalSymlinks(cwd)
subdir, err := filepath.Rel(root, cwd) if err != nil {
if err != nil { return "", false, err
log.Fatal(err) }
goroot, err := filepath.EvalSymlinks(runtime.GOROOT())
if err != nil {
return "", false, err
}
if subdir, err := filepath.Rel(goroot, cwd); err == nil {
if !strings.Contains(subdir, "..") {
return subdir, true, nil
} }
return subdir, true
} }
for _, p := range filepath.SplitList(build.Default.GOPATH) { for _, p := range filepath.SplitList(build.Default.GOPATH) {
if !strings.HasPrefix(cwd, p) { pabs, err := filepath.EvalSymlinks(p)
continue if err != nil {
return "", false, err
} }
subdir, err := filepath.Rel(p, cwd) if subdir, err := filepath.Rel(pabs, cwd); err == nil {
if err == nil { if !strings.Contains(subdir, "..") {
return subdir, false return subdir, false, nil
}
} }
} }
log.Fatalf("the current path %q is not in either GOROOT(%q) or GOPATH(%q)", return "", false, fmt.Errorf("the current path %q is not in either GOROOT(%q) or GOPATH(%q)",
cwd, runtime.GOROOT(), build.Default.GOPATH) cwd, runtime.GOROOT(), build.Default.GOPATH)
return "", false
} }
// adbSyncGoroot ensures that files necessary for testing the Go standard // adbCopyTree copies testdata, go.mod, go.sum files from subdir
// packages are present on the attached device. // and from parent directories all the way up to the root of subdir.
func adbSyncGoroot() { // go.mod and go.sum files are needed for the go tool modules queries,
// and the testdata directories for tests. It is common for tests to
// reach out into testdata from parent packages.
func adbCopyTree(deviceCwd, subdir string) error {
dir := ""
for {
for _, path := range []string{"testdata", "go.mod", "go.sum"} {
path := filepath.Join(dir, path)
if _, err := os.Stat(path); err != nil {
continue
}
devicePath := filepath.Join(deviceCwd, dir)
if err := adb("exec-out", "mkdir", "-p", devicePath); err != nil {
return err
}
if err := adb("push", path, devicePath); err != nil {
return err
}
}
if subdir == "." {
break
}
subdir = filepath.Dir(subdir)
dir = filepath.Join(dir, "..")
}
return nil
}
// adbCopyGoroot clears deviceRoot for previous versions of GOROOT, GOPATH
// and temporary data. Then, it copies relevant parts of GOROOT to the device,
// including the go tool built for android.
// A lock file ensures this only happens once, even with concurrent exec
// wrappers.
func adbCopyGoroot() error {
// Also known by cmd/dist. The bootstrap command deletes the file. // Also known by cmd/dist. The bootstrap command deletes the file.
statPath := filepath.Join(os.TempDir(), "go_android_exec-adb-sync-status") statPath := filepath.Join(os.TempDir(), "go_android_exec-adb-sync-status")
stat, err := os.OpenFile(statPath, os.O_CREATE|os.O_RDWR, 0666) stat, err := os.OpenFile(statPath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil { if err != nil {
log.Fatal(err) return err
} }
defer stat.Close() defer stat.Close()
// Serialize check and syncing. // Serialize check and copying.
if err := syscall.Flock(int(stat.Fd()), syscall.LOCK_EX); err != nil { if err := syscall.Flock(int(stat.Fd()), syscall.LOCK_EX); err != nil {
log.Fatal(err) return err
} }
s, err := ioutil.ReadAll(stat) s, err := ioutil.ReadAll(stat)
if err != nil { if err != nil {
log.Fatal(err) return err
} }
if string(s) == "done" { if string(s) == "done" {
return return nil
}
// Delete GOROOT, GOPATH and any leftover test data.
if err := adb("exec-out", "rm", "-rf", deviceRoot); err != nil {
return err
}
deviceBin := filepath.Join(deviceGoroot, "bin")
if err := adb("exec-out", "mkdir", "-p", deviceBin); err != nil {
return err
} }
devRoot := "/data/local/tmp/goroot"
run("shell", "rm", "-rf", devRoot)
run("shell", "mkdir", "-p", devRoot+"/pkg")
goroot := runtime.GOROOT() goroot := runtime.GOROOT()
// Build go for android.
goCmd := filepath.Join(goroot, "bin", "go") goCmd := filepath.Join(goroot, "bin", "go")
runtimea, err := exec.Command(goCmd, "list", "-f", "{{.Target}}", "runtime").Output() tmpGo, err := ioutil.TempFile("", "go_android_exec-cmd-go-*")
if err != nil { if err != nil {
log.Fatal(err) return err
} }
tmpGo.Close()
defer os.Remove(tmpGo.Name())
if out, err := exec.Command(goCmd, "build", "-o", tmpGo.Name(), "cmd/go").CombinedOutput(); err != nil {
return fmt.Errorf("failed to build go tool for device: %s\n%v", out, err)
}
deviceGo := filepath.Join(deviceBin, "go")
if err := adb("push", tmpGo.Name(), deviceGo); err != nil {
return err
}
for _, dir := range []string{"src", "test", "lib", "api"} {
if err := adb("push", filepath.Join(goroot, dir), filepath.Join(deviceGoroot)); err != nil {
return err
}
}
// Copy only the relevant from pkg.
if err := adb("exec-out", "mkdir", "-p", filepath.Join(deviceGoroot, "pkg", "tool")); err != nil {
return err
}
if err := adb("push", filepath.Join(goroot, "pkg", "include"), filepath.Join(deviceGoroot, "pkg")); err != nil {
return err
}
runtimea, err := exec.Command(goCmd, "list", "-f", "{{.Target}}", "runtime").Output()
pkgdir := filepath.Dir(string(runtimea)) pkgdir := filepath.Dir(string(runtimea))
if pkgdir == "" { if pkgdir == "" {
log.Fatal("could not find android pkg dir") return errors.New("could not find android pkg dir")
} }
for _, dir := range []string{"src", "test", "lib"} { if err := adb("push", pkgdir, filepath.Join(deviceGoroot, "pkg")); err != nil {
run("push", filepath.Join(goroot, dir), filepath.Join(devRoot)) return err
} }
run("push", filepath.Join(pkgdir), filepath.Join(devRoot, "pkg/")) tooldir := filepath.Join(goroot, "pkg", "tool", filepath.Base(pkgdir))
if err := adb("push", tooldir, filepath.Join(deviceGoroot, "pkg", "tool")); err != nil {
return err
}
if _, err := stat.Write([]byte("done")); err != nil { if _, err := stat.Write([]byte("done")); err != nil {
log.Fatal(err) return err
} }
return nil
} }

View file

@ -14,12 +14,17 @@ goos=$(go env GOOS)
libext="so" libext="so"
if [ "$goos" = "darwin" ]; then if [ "$goos" = "darwin" ]; then
libext="dylib" libext="dylib"
elif [ "$goos" = "aix" ]; then
libtext="a"
fi fi
case "$FC" in case "$FC" in
*gfortran*) *gfortran*)
libpath=$(dirname $($FC -print-file-name=libgfortran.$libext)) libpath=$(dirname $($FC -print-file-name=libgfortran.$libext))
export CGO_LDFLAGS="$CGO_LDFLAGS -Wl,-rpath,$libpath -L $libpath" if [ "$goos" != "aix" ]; then
RPATH_FLAG="-Wl,-rpath,$libpath"
fi
export CGO_LDFLAGS="$CGO_LDFLAGS $RPATH_FLAG -L $libpath"
;; ;;
esac esac

View file

@ -46,6 +46,9 @@ func testMain(m *testing.M) int {
} }
func TestTestRun(t *testing.T) { func TestTestRun(t *testing.T) {
if os.Getenv("GOOS") == "android" {
t.Skip("the go tool runs with CGO_ENABLED=0 on the android device")
}
out, err := exec.Command("go", "env", "GOROOT").Output() out, err := exec.Command("go", "env", "GOROOT").Output()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -46,6 +46,9 @@ func testMain(m *testing.M) int {
} }
func TestTestRun(t *testing.T) { func TestTestRun(t *testing.T) {
if os.Getenv("GOOS") == "android" {
t.Skip("subpackage stdio is not available on android")
}
out, err := exec.Command("go", "env", "GOROOT").Output() out, err := exec.Command("go", "env", "GOROOT").Output()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -199,7 +199,7 @@ func testCallbackCallers(t *testing.T) {
t.Errorf("expected %d frames, got %d", len(name), n) t.Errorf("expected %d frames, got %d", len(name), n)
} }
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
f := runtime.FuncForPC(pc[i]) f := runtime.FuncForPC(pc[i] - 1) // TODO: use runtime.CallersFrames
if f == nil { if f == nil {
t.Fatalf("expected non-nil Func for pc %d", pc[i]) t.Fatalf("expected non-nil Func for pc %d", pc[i])
} }

View file

@ -4,8 +4,16 @@
package cgotest package cgotest
import "testing" import (
"runtime"
"testing"
)
func TestSetgid(t *testing.T) { testSetgid(t) } func TestSetgid(t *testing.T) {
if runtime.GOOS == "android" {
t.Skip("unsupported on Android")
}
testSetgid(t)
}
func Test6997(t *testing.T) { test6997(t) } func Test6997(t *testing.T) { test6997(t) }
func TestBuildID(t *testing.T) { testBuildID(t) } func TestBuildID(t *testing.T) { testBuildID(t) }

View file

@ -56,6 +56,7 @@ func Test25143(t *testing.T) { test25143(t) }
func Test26066(t *testing.T) { test26066(t) } func Test26066(t *testing.T) { test26066(t) }
func Test27660(t *testing.T) { test27660(t) } func Test27660(t *testing.T) { test27660(t) }
func Test28896(t *testing.T) { test28896(t) } func Test28896(t *testing.T) { test28896(t) }
func Test29878(t *testing.T) { test29878(t) }
func Test30065(t *testing.T) { test30065(t) } func Test30065(t *testing.T) { test30065(t) }
func TestAlign(t *testing.T) { testAlign(t) } func TestAlign(t *testing.T) { testAlign(t) }
func TestAtol(t *testing.T) { testAtol(t) } func TestAtol(t *testing.T) { testAtol(t) }

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
#include <pthread.h> #include <pthread.h>
#include "_cgo_export.h" #include "_cgo_export.h"

View file

@ -18,8 +18,8 @@ import (
// This is really an os package test but here for convenience. // This is really an os package test but here for convenience.
func testSetEnv(t *testing.T) { func testSetEnv(t *testing.T) {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
// Go uses SetEnvironmentVariable on windows. Howerver, // Go uses SetEnvironmentVariable on windows. However,
// C runtime takes a *copy* at process startup of thei // C runtime takes a *copy* at process startup of the
// OS environment, and stores it in environ/envp. // OS environment, and stores it in environ/envp.
// It is this copy that getenv/putenv manipulate. // It is this copy that getenv/putenv manipulate.
t.Logf("skipping test") t.Logf("skipping test")

View file

@ -46,6 +46,8 @@ func test18146(t *testing.T) {
switch runtime.GOOS { switch runtime.GOOS {
default: default:
setNproc = false setNproc = false
case "aix":
nproc = 9
case "linux": case "linux":
nproc = 6 nproc = 6
case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd": case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd":

View file

@ -11,7 +11,18 @@ package cgotest
// #define ISSUE29781C 0 // #define ISSUE29781C 0
import "C" import "C"
var issue29781X struct{ X int }
func issue29781F(...int) int { return 0 }
func issue29781G() { func issue29781G() {
var p *C.char var p *C.char
C.issue29781F(&p, C.ISSUE29781C+1) C.issue29781F(&p, C.ISSUE29781C+1)
C.issue29781F(nil, (C.int)(
0))
C.issue29781F(&p, (C.int)(0))
C.issue29781F(&p, (C.int)(
0))
C.issue29781F(&p, (C.int)(issue29781X.
X))
} }

View file

@ -0,0 +1,20 @@
// Copyright 2019 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 cgotest
// #include <stdint.h>
// uint64_t issue29878exported(int8_t); // prototype must match
// int16_t issue29878function(uint32_t arg) { return issue29878exported(arg); }
import "C"
import "testing"
func test29878(t *testing.T) {
const arg uint32 = 123 // fits into all integer types
var ret int16 = C.issue29878function(arg) // no conversions needed
if int64(ret) != int64(arg) {
t.Errorf("return value unexpected: got %d, want %d", ret, arg)
}
}

View file

@ -0,0 +1,12 @@
// Copyright 2019 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 cgotest
import "C"
//export issue29878exported
func issue29878exported(arg int8) uint64 {
return uint64(arg)
}

View file

@ -27,7 +27,10 @@ import (
// this shim and move the tests currently located in testdata back into the // this shim and move the tests currently located in testdata back into the
// parent directory. // parent directory.
func TestCrossPackageTests(t *testing.T) { func TestCrossPackageTests(t *testing.T) {
if runtime.GOOS == "darwin" { switch runtime.GOOS {
case "android":
t.Skip("Can't exec cmd/go subprocess on Android.")
case "darwin":
switch runtime.GOARCH { switch runtime.GOARCH {
case "arm", "arm64": case "arm", "arm64":
t.Skip("Can't exec cmd/go subprocess on iOS.") t.Skip("Can't exec cmd/go subprocess on iOS.")
@ -56,7 +59,7 @@ func TestCrossPackageTests(t *testing.T) {
cmd.Args = append(cmd.Args, "-short") cmd.Args = append(cmd.Args, "-short")
} }
cmd.Dir = modRoot cmd.Dir = modRoot
cmd.Env = append(os.Environ(), "GOPATH="+GOPATH) cmd.Env = append(os.Environ(), "GOPATH="+GOPATH, "PWD="+cmd.Dir)
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err == nil { if err == nil {
t.Logf("%s:\n%s", strings.Join(cmd.Args, " "), out) t.Logf("%s:\n%s", strings.Join(cmd.Args, " "), out)

View file

@ -55,7 +55,7 @@ import (
func testSigaltstack(t *testing.T) { func testSigaltstack(t *testing.T) {
switch { switch {
case runtime.GOOS == "solaris", runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64"): case runtime.GOOS == "solaris", runtime.GOOS == "illumos", runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64"):
t.Skipf("switching signal stack not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) t.Skipf("switching signal stack not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
case runtime.GOOS == "darwin" && runtime.GOARCH == "386": case runtime.GOOS == "darwin" && runtime.GOARCH == "386":
t.Skipf("sigaltstack fails on darwin/386") t.Skipf("sigaltstack fails on darwin/386")

12
misc/cgo/test/testdata/issue29563.go vendored Normal file
View file

@ -0,0 +1,12 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !windows
// Issue 29563: internal linker fails on duplicate weak symbols.
// No runtime test; just make sure it compiles.
package cgotest
import _ "cgotest/issue29563"

View file

@ -0,0 +1,13 @@
// Copyright 2019 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 issue29563
//int foo1();
//int foo2();
import "C"
func Bar() int {
return int(C.foo1()) + int(C.foo2())
}

View file

@ -0,0 +1,11 @@
// Copyright 2019 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.
extern int weaksym __attribute__((__weak__));
int weaksym = 42;
int foo1()
{
return weaksym;
}

View file

@ -0,0 +1,11 @@
// Copyright 2019 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.
extern int weaksym __attribute__((__weak__));
int weaksym = 42;
int foo2()
{
return weaksym;
}

14
misc/cgo/test/testdata/issue30527.go vendored Normal file
View file

@ -0,0 +1,14 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Issue 30527: function call rewriting casts untyped
// constants to int because of ":=" usage.
package cgotest
import "cgotest/issue30527"
func issue30527G() {
issue30527.G(nil)
}

19
misc/cgo/test/testdata/issue30527/a.go vendored Normal file
View file

@ -0,0 +1,19 @@
// Copyright 2019 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 issue30527
import "math"
/*
#include <inttypes.h>
static void issue30527F(char **p, uint64_t mod, uint32_t unused) {}
*/
import "C"
func G(p **C.char) {
C.issue30527F(p, math.MaxUint64, 1)
C.issue30527F(p, 1<<64-1, Z)
}

11
misc/cgo/test/testdata/issue30527/b.go vendored Normal file
View file

@ -0,0 +1,11 @@
// Copyright 2019 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 issue30527
const (
X = 1 << iota
Y
Z
)

View file

@ -8,6 +8,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"debug/elf" "debug/elf"
"flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
@ -36,6 +37,11 @@ var GOOS, GOARCH, GOPATH string
var libgodir string var libgodir string
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
flag.Parse()
if testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" {
fmt.Printf("SKIP - short mode and $GO_BUILDER_NAME not set\n")
os.Exit(0)
}
log.SetFlags(log.Lshortfile) log.SetFlags(log.Lshortfile)
os.Exit(testMain(m)) os.Exit(testMain(m))
} }
@ -110,6 +116,11 @@ func testMain(m *testing.M) int {
// TODO(crawshaw): can we do better? // TODO(crawshaw): can we do better?
cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...) cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
} }
if GOOS == "aix" {
// -Wl,-bnoobjreorder is mandatory to keep the same layout
// in .text section.
cc = append(cc, "-Wl,-bnoobjreorder")
}
libbase := GOOS + "_" + GOARCH libbase := GOOS + "_" + GOARCH
if runtime.Compiler == "gccgo" { if runtime.Compiler == "gccgo" {
libbase = "gccgo_" + libgodir + "_fPIC" libbase = "gccgo_" + libgodir + "_fPIC"
@ -119,7 +130,7 @@ func testMain(m *testing.M) int {
if GOARCH == "arm" || GOARCH == "arm64" { if GOARCH == "arm" || GOARCH == "arm64" {
libbase += "_shared" libbase += "_shared"
} }
case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris", "illumos":
libbase += "_shared" libbase += "_shared"
} }
} }
@ -318,8 +329,10 @@ func TestSignalForwarding(t *testing.T) {
} }
func TestSignalForwardingExternal(t *testing.T) { func TestSignalForwardingExternal(t *testing.T) {
if GOOS == "freebsd" { if GOOS == "freebsd" || GOOS == "aix" {
t.Skipf("skipping on %s/%s; signal always goes to the Go runtime", GOOS, GOARCH) t.Skipf("skipping on %s/%s; signal always goes to the Go runtime", GOOS, GOARCH)
} else if GOOS == "darwin" && GOARCH == "amd64" {
t.Skipf("skipping on %s/%s: runtime does not permit SI_USER SIGSEGV", GOOS, GOARCH)
} }
checkSignalForwardingTest(t) checkSignalForwardingTest(t)
@ -518,6 +531,9 @@ func TestExtar(t *testing.T) {
if runtime.Compiler == "gccgo" { if runtime.Compiler == "gccgo" {
t.Skip("skipping -extar test when using gccgo") t.Skip("skipping -extar test when using gccgo")
} }
if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
t.Skip("shell scripts are not executable on iOS hosts")
}
defer func() { defer func() {
os.Remove("libgo4.a") os.Remove("libgo4.a")
@ -594,13 +610,15 @@ func TestPIE(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
f, err := elf.Open("testp" + exeSuffix) if GOOS != "aix" {
if err != nil { f, err := elf.Open("testp" + exeSuffix)
t.Fatal("elf.Open failed: ", err) if err != nil {
} t.Fatal("elf.Open failed: ", err)
defer f.Close() }
if hasDynTag(t, f, elf.DT_TEXTREL) { defer f.Close()
t.Errorf("%s has DT_TEXTREL flag", "testp"+exeSuffix) if hasDynTag(t, f, elf.DT_TEXTREL) {
t.Errorf("%s has DT_TEXTREL flag", "testp"+exeSuffix)
}
} }
} }

View file

@ -14,6 +14,13 @@
#include "libgo4.h" #include "libgo4.h"
#ifdef _AIX
// On AIX, CSIGSTKSZ is too small to handle Go sighandler.
#define CSIGSTKSZ 0x4000
#else
#define CSIGSTKSZ SIGSTKSZ
#endif
static void die(const char* msg) { static void die(const char* msg) {
perror(msg); perror(msg);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -53,12 +60,12 @@ static void* thread1(void* arg __attribute__ ((unused))) {
// Set up an alternate signal stack for this thread. // Set up an alternate signal stack for this thread.
memset(&ss, 0, sizeof ss); memset(&ss, 0, sizeof ss);
ss.ss_sp = malloc(SIGSTKSZ); ss.ss_sp = malloc(CSIGSTKSZ);
if (ss.ss_sp == NULL) { if (ss.ss_sp == NULL) {
die("malloc"); die("malloc");
} }
ss.ss_flags = 0; ss.ss_flags = 0;
ss.ss_size = SIGSTKSZ; ss.ss_size = CSIGSTKSZ;
if (sigaltstack(&ss, NULL) < 0) { if (sigaltstack(&ss, NULL) < 0) {
die("sigaltstack"); die("sigaltstack");
} }
@ -93,7 +100,7 @@ static void* thread1(void* arg __attribute__ ((unused))) {
fprintf(stderr, "sigaltstack disabled on return from Go\n"); fprintf(stderr, "sigaltstack disabled on return from Go\n");
ok = 0; ok = 0;
} else if (nss.ss_sp != ss.ss_sp) { } else if (nss.ss_sp != ss.ss_sp) {
fprintf(stderr, "sigalstack changed on return from Go\n"); fprintf(stderr, "sigaltstack changed on return from Go\n");
ok = 0; ok = 0;
} }
@ -112,12 +119,12 @@ static void* thread2(void* arg __attribute__ ((unused))) {
// Set up an alternate signal stack for this thread. // Set up an alternate signal stack for this thread.
memset(&ss, 0, sizeof ss); memset(&ss, 0, sizeof ss);
ss.ss_sp = malloc(SIGSTKSZ); ss.ss_sp = malloc(CSIGSTKSZ);
if (ss.ss_sp == NULL) { if (ss.ss_sp == NULL) {
die("malloc"); die("malloc");
} }
ss.ss_flags = 0; ss.ss_flags = 0;
ss.ss_size = SIGSTKSZ; ss.ss_size = CSIGSTKSZ;
if (sigaltstack(&ss, NULL) < 0) { if (sigaltstack(&ss, NULL) < 0) {
die("sigaltstack"); die("sigaltstack");
} }
@ -150,7 +157,7 @@ static void* thread2(void* arg __attribute__ ((unused))) {
fprintf(stderr, "sigaltstack disabled on return from Go\n"); fprintf(stderr, "sigaltstack disabled on return from Go\n");
ok = 0; ok = 0;
} else if (nss.ss_sp != ss.ss_sp) { } else if (nss.ss_sp != ss.ss_sp) {
fprintf(stderr, "sigalstack changed on return from Go\n"); fprintf(stderr, "sigaltstack changed on return from Go\n");
ok = 0; ok = 0;
} }

View file

@ -14,6 +14,8 @@
#include "libgo2.h" #include "libgo2.h"
int *nilp;
int main(int argc, char** argv) { int main(int argc, char** argv) {
int verbose; int verbose;
int test; int test;
@ -39,7 +41,7 @@ int main(int argc, char** argv) {
printf("attempting segfault\n"); printf("attempting segfault\n");
} }
volatile int crash = *(int *) 0; *nilp = 0;
break; break;
} }
@ -85,7 +87,7 @@ int main(int argc, char** argv) {
printf("write(2) unexpectedly succeeded\n"); printf("write(2) unexpectedly succeeded\n");
return 0; return 0;
} }
printf("did not receieve SIGPIPE\n"); printf("did not receive SIGPIPE\n");
return 0; return 0;
} }
default: default:

View file

@ -7,12 +7,14 @@ package cshared_test
import ( import (
"bytes" "bytes"
"debug/elf" "debug/elf"
"flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"runtime"
"strings" "strings"
"sync" "sync"
"testing" "testing"
@ -35,6 +37,11 @@ func TestMain(m *testing.M) {
func testMain(m *testing.M) int { func testMain(m *testing.M) int {
log.SetFlags(log.Lshortfile) log.SetFlags(log.Lshortfile)
flag.Parse()
if testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" {
fmt.Printf("SKIP - short mode and $GO_BUILDER_NAME not set\n")
os.Exit(0)
}
GOOS = goEnv("GOOS") GOOS = goEnv("GOOS")
GOARCH = goEnv("GOARCH") GOARCH = goEnv("GOARCH")
@ -45,8 +52,8 @@ func testMain(m *testing.M) int {
} }
androiddir = fmt.Sprintf("/data/local/tmp/testcshared-%d", os.Getpid()) androiddir = fmt.Sprintf("/data/local/tmp/testcshared-%d", os.Getpid())
if GOOS == "android" { if runtime.GOOS != GOOS && GOOS == "android" {
args := append(adbCmd(), "shell", "mkdir", "-p", androiddir) args := append(adbCmd(), "exec-out", "mkdir", "-p", androiddir)
cmd := exec.Command(args[0], args[1:]...) cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
@ -104,7 +111,7 @@ func testMain(m *testing.M) int {
if GOARCH == "arm" || GOARCH == "arm64" { if GOARCH == "arm" || GOARCH == "arm64" {
libgodir += "_shared" libgodir += "_shared"
} }
case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris", "illumos":
libgodir += "_shared" libgodir += "_shared"
} }
cc = append(cc, "-I", filepath.Join("pkg", libgodir)) cc = append(cc, "-I", filepath.Join("pkg", libgodir))
@ -177,7 +184,7 @@ func adbCmd() []string {
} }
func adbPush(t *testing.T, filename string) { func adbPush(t *testing.T, filename string) {
if GOOS != "android" { if runtime.GOOS == GOOS || GOOS != "android" {
return return
} }
args := append(adbCmd(), "push", filename, fmt.Sprintf("%s/%s", androiddir, filename)) args := append(adbCmd(), "push", filename, fmt.Sprintf("%s/%s", androiddir, filename))
@ -191,7 +198,7 @@ func adbRun(t *testing.T, env []string, adbargs ...string) string {
if GOOS != "android" { if GOOS != "android" {
t.Fatalf("trying to run adb command when operating system is not android.") t.Fatalf("trying to run adb command when operating system is not android.")
} }
args := append(adbCmd(), "shell") args := append(adbCmd(), "exec-out")
// Propagate LD_LIBRARY_PATH to the adb shell invocation. // Propagate LD_LIBRARY_PATH to the adb shell invocation.
for _, e := range env { for _, e := range env {
if strings.Index(e, "LD_LIBRARY_PATH=") != -1 { if strings.Index(e, "LD_LIBRARY_PATH=") != -1 {
@ -236,7 +243,7 @@ func run(t *testing.T, extraEnv []string, args ...string) string {
func runExe(t *testing.T, extraEnv []string, args ...string) string { func runExe(t *testing.T, extraEnv []string, args ...string) string {
t.Helper() t.Helper()
if GOOS == "android" { if runtime.GOOS != GOOS && GOOS == "android" {
return adbRun(t, append(os.Environ(), extraEnv...), args...) return adbRun(t, append(os.Environ(), extraEnv...), args...)
} }
return run(t, extraEnv, args...) return run(t, extraEnv, args...)
@ -268,7 +275,7 @@ func createHeaders() error {
return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out) return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
} }
if GOOS == "android" { if runtime.GOOS != GOOS && GOOS == "android" {
args = append(adbCmd(), "push", libgoname, fmt.Sprintf("%s/%s", androiddir, libgoname)) args = append(adbCmd(), "push", libgoname, fmt.Sprintf("%s/%s", androiddir, libgoname))
cmd = exec.Command(args[0], args[1:]...) cmd = exec.Command(args[0], args[1:]...)
out, err = cmd.CombinedOutput() out, err = cmd.CombinedOutput()
@ -298,7 +305,7 @@ func cleanupAndroid() {
if GOOS != "android" { if GOOS != "android" {
return return
} }
args := append(adbCmd(), "shell", "rm", "-rf", androiddir) args := append(adbCmd(), "exec-out", "rm", "-rf", androiddir)
cmd := exec.Command(args[0], args[1:]...) cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
@ -521,7 +528,7 @@ func TestCachedInstall(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
copyFile(t, filepath.Join(tmpdir, "src", "testcshared", "go.mod"), "go.mod") copyFile(t, filepath.Join(tmpdir, "src", "testcshared", "go.mod"), "go.mod")
copyFile(t, filepath.Join(tmpdir, "src", "testcshared", "libgo", "libgo.go"), filepath.Join("libgo", "libgo.go")) copyFile(t, filepath.Join(tmpdir, "src", "testcshared", "libgo", "libgo.go"), filepath.Join("libgo", "libgo.go"))

View file

@ -7,6 +7,7 @@ package plugin_test
import ( import (
"bytes" "bytes"
"context" "context"
"flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
@ -22,8 +23,16 @@ import (
var gcflags string = os.Getenv("GO_GCFLAGS") var gcflags string = os.Getenv("GO_GCFLAGS")
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
flag.Parse()
if testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" {
fmt.Printf("SKIP - short mode and $GO_BUILDER_NAME not set\n")
os.Exit(0)
}
log.SetFlags(log.Lshortfile) log.SetFlags(log.Lshortfile)
os.Exit(testMain(m))
}
func testMain(m *testing.M) int {
// Copy testdata into GOPATH/src/testarchive, along with a go.mod file // Copy testdata into GOPATH/src/testarchive, along with a go.mod file
// declaring the same path. // declaring the same path.
@ -77,7 +86,7 @@ func TestMain(m *testing.M) {
goCmd(nil, "build", "-buildmode=plugin", "-o=unnamed2.so", "./unnamed2/main.go") goCmd(nil, "build", "-buildmode=plugin", "-o=unnamed2.so", "./unnamed2/main.go")
goCmd(nil, "build", "-o", "host.exe", "./host") goCmd(nil, "build", "-o", "host.exe", "./host")
os.Exit(m.Run()) return m.Run()
} }
func goCmd(t *testing.T, op string, args ...string) { func goCmd(t *testing.T, op string, args ...string) {

View file

@ -5,9 +5,10 @@
package main package main
import ( import (
"testplugin/iface_i"
"log" "log"
"plugin" "plugin"
"testplugin/iface_i"
) )
func main() { func main() {

View file

@ -8,8 +8,9 @@ package main
import "C" import "C"
import ( import (
"testplugin/common"
"reflect" "reflect"
"testplugin/common"
) )
func F() int { func F() int {

View file

@ -12,9 +12,10 @@ import "C"
// void cfunc() {} // uses cgo_topofstack // void cfunc() {} // uses cgo_topofstack
import ( import (
"testplugin/common"
"reflect" "reflect"
"strings" "strings"
"testplugin/common"
) )
func init() { func init() {

View file

@ -1,10 +1,11 @@
package main package main
import ( import (
"testshared/depBase"
"os" "os"
"reflect" "reflect"
"runtime" "runtime"
"testshared/depBase"
) )
// Having a function declared in the main package triggered // Having a function declared in the main package triggered

View file

@ -25,7 +25,9 @@ func requireTestSOSupported(t *testing.T) {
t.Skip("No exec facility on iOS.") t.Skip("No exec facility on iOS.")
} }
case "ppc64": case "ppc64":
t.Skip("External linking not implemented on ppc64 (issue #8912).") if runtime.GOOS == "linux" {
t.Skip("External linking not implemented on aix/ppc64 (issue #8912).")
}
case "mips64le", "mips64": case "mips64le", "mips64":
t.Skip("External linking not implemented on mips64.") t.Skip("External linking not implemented on mips64.")
} }
@ -80,6 +82,8 @@ func TestSO(t *testing.T) {
case "windows": case "windows":
ext = "dll" ext = "dll"
args = append(args, "-DEXPORT_DLL") args = append(args, "-DEXPORT_DLL")
case "aix":
ext = "so.1"
} }
sofname := "libcgosotest." + ext sofname := "libcgosotest." + ext
args = append(args, "-o", sofname, "cgoso_c.c") args = append(args, "-o", sofname, "cgoso_c.c")
@ -93,6 +97,16 @@ func TestSO(t *testing.T) {
} }
t.Logf("%s:\n%s", strings.Join(cmd.Args, " "), out) t.Logf("%s:\n%s", strings.Join(cmd.Args, " "), out)
if runtime.GOOS == "aix" {
// Shared object must be wrapped by an archive
cmd = exec.Command("ar", "-X64", "-q", "libcgosotest.a", "libcgosotest.so.1")
cmd.Dir = modRoot
out, err = cmd.CombinedOutput()
if err != nil {
t.Fatalf("%s: %s\n%s", strings.Join(cmd.Args, " "), err, out)
}
}
cmd = exec.Command("go", "build", "-o", "main.exe", "main.go") cmd = exec.Command("go", "build", "-o", "main.exe", "main.go")
cmd.Dir = modRoot cmd.Dir = modRoot
cmd.Env = append(os.Environ(), "GOPATH="+GOPATH) cmd.Env = append(os.Environ(), "GOPATH="+GOPATH)

View file

@ -4,7 +4,7 @@
#include "_cgo_export.h" #include "_cgo_export.h"
#ifdef WIN32 #if defined(WIN32) || defined(_AIX)
extern void setCallback(void *); extern void setCallback(void *);
void init() { void init() {
setCallback(goCallback); setCallback(goCallback);

View file

@ -15,6 +15,7 @@ package cgosotest
#cgo netbsd LDFLAGS: -L. libcgosotest.so #cgo netbsd LDFLAGS: -L. libcgosotest.so
#cgo darwin LDFLAGS: -L. libcgosotest.dylib #cgo darwin LDFLAGS: -L. libcgosotest.dylib
#cgo windows LDFLAGS: -L. libcgosotest.dll #cgo windows LDFLAGS: -L. libcgosotest.dll
#cgo aix LDFLAGS: -L. -l cgosotest
void init(void); void init(void);
void sofunc(void); void sofunc(void);

View file

@ -14,6 +14,15 @@ __declspec(dllexport) void setCallback(void *f)
goCallback = (void (*)())f; goCallback = (void (*)())f;
} }
__declspec(dllexport) void sofunc(void); __declspec(dllexport) void sofunc(void);
#elif defined(_AIX)
// AIX doesn't allow the creation of a shared object with an
// undefined symbol. It's possible to bypass this problem by
// using -Wl,-G and -Wl,-brtl option which allows run-time linking.
// However, that's not how most of AIX shared object works.
// Therefore, it's better to consider goCallback as a pointer and
// to set up during an init function.
void (*goCallback)(void);
void setCallback(void *f) { goCallback = f; }
#else #else
extern void goCallback(void); extern void goCallback(void);
void setCallback(void *f) { (void)f; } void setCallback(void *f) { (void)f; }

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build dragonfly freebsd linux netbsd solaris // +build aix dragonfly freebsd linux netbsd solaris
package cgosotest package cgosotest

View file

@ -25,7 +25,9 @@ func requireTestSOSupported(t *testing.T) {
t.Skip("No exec facility on iOS.") t.Skip("No exec facility on iOS.")
} }
case "ppc64": case "ppc64":
t.Skip("External linking not implemented on ppc64 (issue #8912).") if runtime.GOOS == "linux" {
t.Skip("External linking not implemented on aix/ppc64 (issue #8912).")
}
case "mips64le", "mips64": case "mips64le", "mips64":
t.Skip("External linking not implemented on mips64.") t.Skip("External linking not implemented on mips64.")
} }
@ -80,6 +82,8 @@ func TestSO(t *testing.T) {
case "windows": case "windows":
ext = "dll" ext = "dll"
args = append(args, "-DEXPORT_DLL") args = append(args, "-DEXPORT_DLL")
case "aix":
ext = "so.1"
} }
sofname := "libcgosotest." + ext sofname := "libcgosotest." + ext
args = append(args, "-o", sofname, "cgoso_c.c") args = append(args, "-o", sofname, "cgoso_c.c")
@ -93,6 +97,16 @@ func TestSO(t *testing.T) {
} }
t.Logf("%s:\n%s", strings.Join(cmd.Args, " "), out) t.Logf("%s:\n%s", strings.Join(cmd.Args, " "), out)
if runtime.GOOS == "aix" {
// Shared object must be wrapped by an archive
cmd = exec.Command("ar", "-X64", "-q", "libcgosotest.a", "libcgosotest.so.1")
cmd.Dir = modRoot
out, err = cmd.CombinedOutput()
if err != nil {
t.Fatalf("%s: %s\n%s", strings.Join(cmd.Args, " "), err, out)
}
}
cmd = exec.Command("go", "build", "-o", "main.exe", "main.go") cmd = exec.Command("go", "build", "-o", "main.exe", "main.go")
cmd.Dir = modRoot cmd.Dir = modRoot
cmd.Env = append(os.Environ(), "GOPATH="+GOPATH) cmd.Env = append(os.Environ(), "GOPATH="+GOPATH)

View file

@ -19,6 +19,7 @@ package cgosotest
#cgo netbsd LDFLAGS: -L. libcgosotest.so #cgo netbsd LDFLAGS: -L. libcgosotest.so
#cgo darwin LDFLAGS: -L. libcgosotest.dylib #cgo darwin LDFLAGS: -L. libcgosotest.dylib
#cgo windows LDFLAGS: -L. libcgosotest.dll #cgo windows LDFLAGS: -L. libcgosotest.dll
#cgo aix LDFLAGS: -L. -l cgosotest
#include "cgoso_c.h" #include "cgoso_c.h"

View file

@ -1,26 +0,0 @@
#!/bin/sh
# Copyright 2012 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.
# git gofmt pre-commit hook
#
# To use, store as .git/hooks/pre-commit inside your repository and make sure
# it has execute permissions.
#
# This script does not handle file names that contain spaces.
gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '\.go$')
[ -z "$gofiles" ] && exit 0
unformatted=$(gofmt -l $gofiles)
[ -z "$unformatted" ] && exit 0
# Some files are not gofmt'd. Print message and fail.
echo >&2 "Go files must be formatted with gofmt. Please run:"
for fn in $unformatted; do
echo >&2 " gofmt -w $PWD/$fn"
done
exit 1

11
misc/go.mod Normal file
View file

@ -0,0 +1,11 @@
// Module misc contains tests and binaries that pertain to specific build modes
// (cgo) and platforms (Android and iOS).
//
// The 'run' scripts in ../src execute these tests and binaries, which need to
// be in a module in order to build and run successfully in module mode.
// (Otherwise, they lack well-defined import paths, and module mode unlike
// GOPATH mode does not synthesize import paths from the absolute working
// directory.)
module misc
go 1.12

View file

@ -31,9 +31,10 @@ which will output something similar to
If you have multiple devices connected, specify the device UDID with the GOIOS_DEVICE_ID If you have multiple devices connected, specify the device UDID with the GOIOS_DEVICE_ID
variable. Use `idevice_id -l` to list all available UDIDs. variable. Use `idevice_id -l` to list all available UDIDs.
Finally, to run the standard library tests, run iostest.bash with GOARCH set. For example, Finally, to run the standard library tests, run all.bash as usual, but with the compiler
set to the clang wrapper that invokes clang for iOS. For example,
GOARCH=arm64 ./iostest.bash GOARCH=arm64 CGO_ENABLED=1 CC_FOR_TARGET=$(pwd)/../misc/ios/clangwrap.sh ./all.bash
To use the go tool directly to run programs and tests, put $GOROOT/bin into PATH to ensure To use the go tool directly to run programs and tests, put $GOROOT/bin into PATH to ensure
the go_darwin_$GOARCH_exec wrapper is found. For example, to run the archive/tar tests the go_darwin_$GOARCH_exec wrapper is found. For example, to run the archive/tar tests

View file

@ -467,8 +467,8 @@ func idevCmd(cmd *exec.Cmd) *exec.Cmd {
func run(appdir, bundleID string, args []string) error { func run(appdir, bundleID string, args []string) error {
var env []string var env []string
for _, e := range os.Environ() { for _, e := range os.Environ() {
// Don't override TMPDIR on the device. // Don't override TMPDIR, HOME, GOCACHE on the device.
if strings.HasPrefix(e, "TMPDIR=") { if strings.HasPrefix(e, "TMPDIR=") || strings.HasPrefix(e, "HOME=") || strings.HasPrefix(e, "GOCACHE=") {
continue continue
} }
env = append(env, e) env = append(env, e)
@ -633,8 +633,16 @@ func subdir() (pkgpath string, underGoRoot bool, err error) {
if err != nil { if err != nil {
return "", false, err return "", false, err
} }
if root := runtime.GOROOT(); strings.HasPrefix(cwd, root) { cwd, err = filepath.EvalSymlinks(cwd)
subdir, err := filepath.Rel(root, cwd) if err != nil {
log.Fatal(err)
}
goroot, err := filepath.EvalSymlinks(runtime.GOROOT())
if err != nil {
return "", false, err
}
if strings.HasPrefix(cwd, goroot) {
subdir, err := filepath.Rel(goroot, cwd)
if err != nil { if err != nil {
return "", false, err return "", false, err
} }
@ -642,10 +650,14 @@ func subdir() (pkgpath string, underGoRoot bool, err error) {
} }
for _, p := range filepath.SplitList(build.Default.GOPATH) { for _, p := range filepath.SplitList(build.Default.GOPATH) {
if !strings.HasPrefix(cwd, p) { pabs, err := filepath.EvalSymlinks(p)
if err != nil {
return "", false, err
}
if !strings.HasPrefix(cwd, pabs) {
continue continue
} }
subdir, err := filepath.Rel(p, cwd) subdir, err := filepath.Rel(pabs, cwd)
if err == nil { if err == nil {
return subdir, false, nil return subdir, false, nil
} }

View file

@ -1,6 +1,6 @@
# This file maps Internet media types to unique file extension(s). # This file maps Internet media types to unique file extension(s).
# Although created for httpd, this file is used by many software systems # Although created for httpd, this file is used by many software systems
# and has been placed in the public domain for unlimited redisribution. # and has been placed in the public domain for unlimited redistribution.
# #
# The table below contains both registered and (common) unregistered types. # The table below contains both registered and (common) unregistered types.
# A type that has no unique extension can be ignored -- they are listed # A type that has no unique extension can be ignored -- they are listed

View file

@ -48,43 +48,33 @@ go src=..
pprof pprof
internal internal
binutils binutils
testdata
+
driver
testdata
+
graph
testdata
+
report
testdata
+
profile
testdata
+ +
driver
+
graph
+
report
+
profile
+
ianlancetaylor ianlancetaylor
demangle demangle
testdata +
+
golang.org golang.org
x x
arch arch
arm arm
armasm armasm
testdata +
+
arm64 arm64
arm64asm arm64asm
testdata +
+
x86 x86
x86asm x86asm
testdata +
+
ppc64 ppc64
ppc64asm ppc64asm
testdata +
+
archive archive
tar tar
testdata testdata
@ -107,6 +97,9 @@ go src=..
+ +
zlib zlib
crypto crypto
ed25519
testdata
+
rsa rsa
testdata testdata
+ +

View file

@ -0,0 +1,80 @@
// Copyright 2019 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 reboot_test
import (
"io"
"os"
"path/filepath"
"strings"
)
// overlayDir makes a minimal-overhead copy of srcRoot in which new files may be added.
//
// TODO: Once we no longer need to support the misc module in GOPATH mode,
// factor this function out into a package to reduce duplication.
func overlayDir(dstRoot, srcRoot string) error {
dstRoot = filepath.Clean(dstRoot)
if err := os.MkdirAll(dstRoot, 0777); err != nil {
return err
}
// If we don't use the absolute path here, exec'ing make.bash fails with
// “too many levels of symbolic links”.
symBase, err := filepath.Abs(srcRoot)
if err != nil {
return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
if err != nil || srcPath == srcRoot {
return err
}
suffix := strings.TrimPrefix(srcPath, srcRoot)
for len(suffix) > 0 && suffix[0] == filepath.Separator {
suffix = suffix[1:]
}
dstPath := filepath.Join(dstRoot, suffix)
perm := info.Mode() & os.ModePerm
if info.Mode()&os.ModeSymlink != 0 {
info, err = os.Stat(srcPath)
if err != nil {
return err
}
perm = info.Mode() & os.ModePerm
}
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
return os.Mkdir(dstPath, perm)
}
// If the OS supports symlinks, use them instead of copying bytes.
if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
return nil
}
// Otherwise, copy the bytes.
src, err := os.Open(srcPath)
if err != nil {
return err
}
defer src.Close()
dst, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
if err != nil {
return err
}
_, err = io.Copy(dst, src)
if closeErr := dst.Close(); err == nil {
err = closeErr
}
return err
})
}

View file

@ -0,0 +1,52 @@
// Copyright 2019 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 reboot_test verifies that the current GOROOT can be used to bootstrap
// itself.
package reboot_test
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"testing"
)
func TestRepeatBootstrap(t *testing.T) {
goroot, err := ioutil.TempDir("", "reboot-goroot")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(goroot)
gorootSrc := filepath.Join(goroot, "src")
if err := overlayDir(gorootSrc, filepath.Join(runtime.GOROOT(), "src")); err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(goroot, "VERSION"), []byte(runtime.Version()), 0666); err != nil {
t.Fatal(err)
}
var makeScript string
switch runtime.GOOS {
case "windows":
makeScript = "make.bat"
case "plan9":
makeScript = "make.rc"
default:
makeScript = "make.bash"
}
cmd := exec.Command(filepath.Join(runtime.GOROOT(), "src", makeScript))
cmd.Dir = gorootSrc
cmd.Env = append(os.Environ(), "GOROOT=", "GOROOT_BOOTSTRAP="+runtime.GOROOT())
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
if err := cmd.Run(); err != nil {
t.Fatal(err)
}
}

View file

@ -3,6 +3,15 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
(() => { (() => {
// Map multiple JavaScript environments to a single common API,
// preferring web standards over Node.js API.
//
// Environments considered:
// - Browsers
// - Node.js
// - Electron
// - Parcel
if (typeof global !== "undefined") { if (typeof global !== "undefined") {
// global already exists // global already exists
} else if (typeof window !== "undefined") { } else if (typeof window !== "undefined") {
@ -13,30 +22,15 @@
throw new Error("cannot export Go (neither global, window nor self is defined)"); throw new Error("cannot export Go (neither global, window nor self is defined)");
} }
// Map web browser API and Node.js API to a single common API (preferring web standards over Node.js API). if (!global.require && typeof require !== "undefined") {
const isNodeJS = global.process && global.process.title === "node";
if (isNodeJS) {
global.require = require; global.require = require;
}
if (!global.fs && global.require) {
global.fs = require("fs"); global.fs = require("fs");
}
const nodeCrypto = require("crypto"); if (!global.fs) {
global.crypto = {
getRandomValues(b) {
nodeCrypto.randomFillSync(b);
},
};
global.performance = {
now() {
const [sec, nsec] = process.hrtime();
return sec * 1000 + nsec / 1000000;
},
};
const util = require("util");
global.TextEncoder = util.TextEncoder;
global.TextDecoder = util.TextDecoder;
} else {
let outputBuf = ""; let outputBuf = "";
global.fs = { global.fs = {
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
@ -72,6 +66,34 @@
}; };
} }
if (!global.crypto) {
const nodeCrypto = require("crypto");
global.crypto = {
getRandomValues(b) {
nodeCrypto.randomFillSync(b);
},
};
}
if (!global.performance) {
global.performance = {
now() {
const [sec, nsec] = process.hrtime();
return sec * 1000 + nsec / 1000000;
},
};
}
if (!global.TextEncoder) {
global.TextEncoder = require("util").TextEncoder;
}
if (!global.TextDecoder) {
global.TextDecoder = require("util").TextDecoder;
}
// End of polyfills for common API.
const encoder = new TextEncoder("utf-8"); const encoder = new TextEncoder("utf-8");
const decoder = new TextDecoder("utf-8"); const decoder = new TextDecoder("utf-8");
@ -243,7 +265,15 @@
const id = this._nextCallbackTimeoutID; const id = this._nextCallbackTimeoutID;
this._nextCallbackTimeoutID++; this._nextCallbackTimeoutID++;
this._scheduledTimeouts.set(id, setTimeout( this._scheduledTimeouts.set(id, setTimeout(
() => { this._resume(); }, () => {
this._resume();
while (this._scheduledTimeouts.has(id)) {
// for some reason Go failed to register the timeout event, log and try again
// (temporary workaround for https://github.com/golang/go/issues/28975)
console.warn("scheduleTimeoutEvent: missed timeout event");
this._resume();
}
},
getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early
)); ));
mem().setInt32(sp + 16, id, true); mem().setInt32(sp + 16, id, true);
@ -385,9 +415,13 @@
let offset = 4096; let offset = 4096;
const strPtr = (str) => { const strPtr = (str) => {
let ptr = offset; const ptr = offset;
new Uint8Array(mem.buffer, offset, str.length + 1).set(encoder.encode(str + "\0")); const bytes = encoder.encode(str + "\0");
offset += str.length + (8 - (str.length % 8)); new Uint8Array(mem.buffer, offset, bytes.length).set(bytes);
offset += bytes.length;
if (offset % 8 !== 0) {
offset += 8 - (offset % 8);
}
return ptr; return ptr;
}; };
@ -439,9 +473,15 @@
} }
} }
if (isNodeJS) { if (
global.require &&
global.require.main === module &&
global.process &&
global.process.versions &&
!global.process.versions.electron
) {
if (process.argv.length < 3) { if (process.argv.length < 3) {
process.stderr.write("usage: go_js_wasm_exec [wasm binary] [arguments]\n"); console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
process.exit(1); process.exit(1);
} }
@ -459,7 +499,8 @@
}); });
return go.run(result.instance); return go.run(result.instance);
}).catch((err) => { }).catch((err) => {
throw err; console.error(err);
process.exit(1);
}); });
} }
})(); })();

54
src/README.vendor Normal file
View file

@ -0,0 +1,54 @@
Vendoring in std and cmd
========================
The Go command maintains copies of external packages needed by the
standard library in the src/vendor and src/cmd/vendor directories.
In GOPATH mode, imports of vendored packages are resolved to these
directories following normal vendor directory logic
(see golang.org/s/go15vendor).
In module mode, std and cmd are modules (defined in src/go.mod and
src/cmd/go.mod). When a package outside std or cmd is imported
by a package inside std or cmd, the import path is interpreted
as if it had a "vendor/" prefix. For example, within "crypto/tls",
an import of "golang.org/x/crypto/cryptobyte" resolves to
"vendor/golang.org/x/crypto/cryptobyte". When a package with the
same path is imported from a package outside std or cmd, it will
be resolved normally. Consequently, a binary may be built with two
copies of a package at different versions if the package is
imported normally and vendored by the standard library.
Vendored packages are internally renamed with a "vendor/" prefix
to preserve the invariant that all packages have distinct paths.
This is necessary to avoid compiler and linker conflicts. Adding
a "vendor/" prefix also maintains the invariant that standard
library packages begin with a dotless path element.
The module requirements of std and cmd do not influence version
selection in other modules. They are only considered when running
module commands like 'go get' and 'go mod vendor' from a directory
in GOROOT/src.
Maintaining vendor directories
==============================
Before updating vendor directories, ensure that module mode is enabled.
Make sure GO111MODULE=off is not set ('on' or 'auto' should work).
Requirements may be added, updated, and removed with 'go get'.
The vendor directory may be updated with 'go mod vendor'.
A typical sequence might be:
cd src
go get -m golang.org/x/net@latest
go mod tidy
go mod vendor
Use caution when passing '-u' to 'go get'. The '-u' flag updates
modules providing all transitively imported packages, not just
the target module.
Note that 'go mod vendor' only copies packages that are transitively
imported by packages in the current module. If a new package is needed,
it should be imported before running 'go mod vendor'.

View file

@ -1,37 +0,0 @@
#!/usr/bin/env bash
# Copyright 2014 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.
# For testing Android.
set -e
ulimit -c 0 # no core files
if [ ! -f make.bash ]; then
echo 'androidtest.bash must be run from $GOROOT/src' 1>&2
exit 1
fi
if [ -z $GOOS ]; then
export GOOS=android
fi
if [ "$GOOS" != "android" ]; then
echo "androidtest.bash requires GOOS=android, got GOOS=$GOOS" 1>&2
exit 1
fi
if [ -n "$GOARM" ] && [ "$GOARM" != "7" ]; then
echo "android only supports GOARM=7, got GOARM=$GOARM" 1>&2
exit 1
fi
export CGO_ENABLED=1
unset GOBIN
export GOROOT=$(dirname $(pwd))
# Put the exec wrapper into PATH
export PATH=$GOROOT/bin:$PATH
# Run standard tests.
bash all.bash

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build linux dragonfly openbsd solaris // +build aix linux dragonfly openbsd solaris
package tar package tar

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build linux darwin dragonfly freebsd openbsd netbsd solaris // +build aix linux darwin dragonfly freebsd openbsd netbsd solaris
package tar package tar
@ -54,6 +54,11 @@ func statUnix(fi os.FileInfo, h *Header) error {
if h.Typeflag == TypeChar || h.Typeflag == TypeBlock { if h.Typeflag == TypeChar || h.Typeflag == TypeBlock {
dev := uint64(sys.Rdev) // May be int32 or uint32 dev := uint64(sys.Rdev) // May be int32 or uint32
switch runtime.GOOS { switch runtime.GOOS {
case "aix":
var major, minor uint32
major = uint32((dev & 0x3fffffff00000000) >> 32)
minor = uint32((dev & 0x00000000ffffffff) >> 0)
h.Devmajor, h.Devminor = int64(major), int64(minor)
case "linux": case "linux":
// Copied from golang.org/x/sys/unix/dev_linux.go. // Copied from golang.org/x/sys/unix/dev_linux.go.
major := uint32((dev & 0x00000000000fff00) >> 8) major := uint32((dev & 0x00000000000fff00) >> 8)

View file

@ -154,10 +154,15 @@ func (fi headerFileInfo) Size() int64 {
} }
return int64(fi.fh.UncompressedSize) return int64(fi.fh.UncompressedSize)
} }
func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() } func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
func (fi headerFileInfo) ModTime() time.Time { return fi.fh.ModTime() } func (fi headerFileInfo) ModTime() time.Time {
func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() } if fi.fh.Modified.IsZero() {
func (fi headerFileInfo) Sys() interface{} { return fi.fh } return fi.fh.ModTime()
}
return fi.fh.Modified.UTC()
}
func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() }
func (fi headerFileInfo) Sys() interface{} { return fi.fh }
// FileInfoHeader creates a partially-populated FileHeader from an // FileInfoHeader creates a partially-populated FileHeader from an
// os.FileInfo. // os.FileInfo.

View file

@ -114,6 +114,47 @@ func TestFileHeaderRoundTrip64(t *testing.T) {
testHeaderRoundTrip(fh, uint32max, fh.UncompressedSize64, t) testHeaderRoundTrip(fh, uint32max, fh.UncompressedSize64, t)
} }
func TestFileHeaderRoundTripModified(t *testing.T) {
fh := &FileHeader{
Name: "foo.txt",
UncompressedSize: 987654321,
Modified: time.Now().Local(),
ModifiedTime: 1234,
ModifiedDate: 5678,
}
fi := fh.FileInfo()
fh2, err := FileInfoHeader(fi)
if err != nil {
t.Fatal(err)
}
if got, want := fh2.Modified, fh.Modified.UTC(); got != want {
t.Errorf("Modified: got %s, want %s\n", got, want)
}
if got, want := fi.ModTime(), fh.Modified.UTC(); got != want {
t.Errorf("Modified: got %s, want %s\n", got, want)
}
}
func TestFileHeaderRoundTripWithoutModified(t *testing.T) {
fh := &FileHeader{
Name: "foo.txt",
UncompressedSize: 987654321,
ModifiedTime: 1234,
ModifiedDate: 5678,
}
fi := fh.FileInfo()
fh2, err := FileInfoHeader(fi)
if err != nil {
t.Fatal(err)
}
if got, want := fh2.ModTime(), fh.ModTime(); got != want {
t.Errorf("Modified: got %s, want %s\n", got, want)
}
if got, want := fi.ModTime(), fh.ModTime(); got != want {
t.Errorf("Modified: got %s, want %s\n", got, want)
}
}
type repeatedByte struct { type repeatedByte struct {
off int64 off int64
b byte b byte

View file

@ -45,10 +45,11 @@ fi
unset GOROOT unset GOROOT
src=$(cd .. && pwd) src=$(cd .. && pwd)
echo "#### Copying to $targ" echo "#### Copying to $targ"
cp -R "$src" "$targ" cp -Rp "$src" "$targ"
cd "$targ" cd "$targ"
echo echo
echo "#### Cleaning $targ" echo "#### Cleaning $targ"
chmod -R +w .
rm -f .gitignore rm -f .gitignore
if [ -e .git ]; then if [ -e .git ]; then
git clean -f -d git clean -f -d
@ -72,6 +73,7 @@ if [ "$goos" = "$gohostos" -a "$goarch" = "$gohostarch" ]; then
# prepare a clean toolchain for others. # prepare a clean toolchain for others.
true true
else else
rm -f bin/go_${goos}_${goarch}_exec
mv bin/*_*/* bin mv bin/*_*/* bin
rmdir bin/*_* rmdir bin/*_*
rm -rf "pkg/${gohostos}_${gohostarch}" "pkg/tool/${gohostos}_${gohostarch}" rm -rf "pkg/${gohostos}_${gohostarch}" "pkg/tool/${gohostos}_${gohostarch}"

View file

@ -94,6 +94,9 @@ func ExampleScanner_emptyFinalToken() {
return i + 1, data[:i], nil return i + 1, data[:i], nil
} }
} }
if !atEOF {
return 0, nil, nil
}
// There is one final token to be delivered, which may be the empty string. // There is one final token to be delivered, which may be the empty string.
// Returning bufio.ErrFinalToken here tells Scan there are no more tokens after this // Returning bufio.ErrFinalToken here tells Scan there are no more tokens after this
// but does not trigger an error to be returned from Scan itself. // but does not trigger an error to be returned from Scan itself.

View file

@ -73,7 +73,11 @@ do
export GOARCH=386 export GOARCH=386
export GO386=387 export GO386=387
fi fi
if ! "$GOROOT/bin/go" build -a std cmd; then
# Build and vet everything.
# cmd/go/internal/work/exec.go enables the same vet flags during go test of std cmd
# and should be kept in sync with any vet flag changes here.
if ! "$GOROOT/bin/go" build std cmd || ! "$GOROOT/bin/go" vet -unsafeptr=false std cmd; then
failed=true failed=true
if $sete; then if $sete; then
exit 1 exit 1

View file

@ -151,7 +151,7 @@ func delete(m map[Type]Type1, key Type)
// Slice, or map: the number of elements in v; if v is nil, len(v) is zero. // Slice, or map: the number of elements in v; if v is nil, len(v) is zero.
// String: the number of bytes in v. // String: the number of bytes in v.
// Channel: the number of elements queued (unread) in the channel buffer; // Channel: the number of elements queued (unread) in the channel buffer;
// if v is nil, len(v) is zero. // if v is nil, len(v) is zero.
// For some arguments, such as a string literal or a simple array expression, the // For some arguments, such as a string literal or a simple array expression, the
// result can be a constant. See the Go language specification's "Length and // result can be a constant. See the Go language specification's "Length and
// capacity" section for details. // capacity" section for details.
@ -226,10 +226,9 @@ func close(c chan<- Type)
// invocation of F then behaves like a call to panic, terminating G's // invocation of F then behaves like a call to panic, terminating G's
// execution and running any deferred functions. This continues until all // execution and running any deferred functions. This continues until all
// functions in the executing goroutine have stopped, in reverse order. At // functions in the executing goroutine have stopped, in reverse order. At
// that point, the program is terminated and the error condition is reported, // that point, the program is terminated with a non-zero exit code. This
// including the value of the argument to panic. This termination sequence // termination sequence is called panicking and can be controlled by the
// is called panicking and can be controlled by the built-in function // built-in function recover.
// recover.
func panic(v interface{}) func panic(v interface{})
// The recover built-in function allows a program to manage behavior of a // The recover built-in function allows a program to manage behavior of a

View file

@ -12,23 +12,12 @@ import (
"unicode/utf8" "unicode/utf8"
) )
// Equal returns a boolean reporting whether a and b // Equal reports whether a and b
// are the same length and contain the same bytes. // are the same length and contain the same bytes.
// A nil argument is equivalent to an empty slice. // A nil argument is equivalent to an empty slice.
func Equal(a, b []byte) bool { func Equal(a, b []byte) bool {
return bytealg.Equal(a, b) // Neither cmd/compile nor gccgo allocates for these string conversions.
} return string(a) == string(b)
func equalPortable(a, b []byte) bool {
if len(a) != len(b) {
return false
}
for i, c := range a {
if c != b[i] {
return false
}
}
return true
} }
// Compare returns an integer comparing two byte slices lexicographically. // Compare returns an integer comparing two byte slices lexicographically.
@ -114,12 +103,34 @@ func indexBytePortable(s []byte, c byte) int {
// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s. // LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
func LastIndex(s, sep []byte) int { func LastIndex(s, sep []byte) int {
n := len(sep) n := len(sep)
if n == 0 { switch {
case n == 0:
return len(s) return len(s)
case n == 1:
return LastIndexByte(s, sep[0])
case n == len(s):
if Equal(s, sep) {
return 0
}
return -1
case n > len(s):
return -1
} }
c := sep[0] // Rabin-Karp search from the end of the string
for i := len(s) - n; i >= 0; i-- { hashss, pow := hashStrRev(sep)
if s[i] == c && (n == 1 || Equal(s[i:i+n], sep)) { last := len(s) - n
var h uint32
for i := len(s) - 1; i >= last; i-- {
h = h*primeRK + uint32(s[i])
}
if h == hashss && Equal(s[last:], sep) {
return last
}
for i := last - 1; i >= 0; i-- {
h *= primeRK
h += uint32(s[i])
h -= pow * uint32(s[i+n])
if h == hashss && Equal(s[i:i+n], sep) {
return i return i
} }
} }
@ -477,13 +488,16 @@ func Map(mapping func(r rune) rune, s []byte) []byte {
// It panics if count is negative or if // It panics if count is negative or if
// the result of (len(b) * count) overflows. // the result of (len(b) * count) overflows.
func Repeat(b []byte, count int) []byte { func Repeat(b []byte, count int) []byte {
if count == 0 {
return []byte{}
}
// Since we cannot return an error on overflow, // Since we cannot return an error on overflow,
// we should panic if the repeat will generate // we should panic if the repeat will generate
// an overflow. // an overflow.
// See Issue golang.org/issue/16237. // See Issue golang.org/issue/16237.
if count < 0 { if count < 0 {
panic("bytes: negative Repeat count") panic("bytes: negative Repeat count")
} else if count > 0 && len(b)*count/count != len(b) { } else if len(b)*count/count != len(b) {
panic("bytes: Repeat count causes overflow") panic("bytes: Repeat count causes overflow")
} }
@ -496,11 +510,66 @@ func Repeat(b []byte, count int) []byte {
return nb return nb
} }
// ToUpper treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters within it mapped to their upper case. // ToUpper returns a copy of the byte slice s with all Unicode letters mapped to
func ToUpper(s []byte) []byte { return Map(unicode.ToUpper, s) } // their upper case.
func ToUpper(s []byte) []byte {
isASCII, hasLower := true, false
for i := 0; i < len(s); i++ {
c := s[i]
if c >= utf8.RuneSelf {
isASCII = false
break
}
hasLower = hasLower || ('a' <= c && c <= 'z')
}
// ToLower treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their lower case. if isASCII { // optimize for ASCII-only byte slices.
func ToLower(s []byte) []byte { return Map(unicode.ToLower, s) } if !hasLower {
// Just return a copy.
return append([]byte(""), s...)
}
b := make([]byte, len(s))
for i := 0; i < len(s); i++ {
c := s[i]
if 'a' <= c && c <= 'z' {
c -= 'a' - 'A'
}
b[i] = c
}
return b
}
return Map(unicode.ToUpper, s)
}
// ToLower returns a copy of the byte slice s with all Unicode letters mapped to
// their lower case.
func ToLower(s []byte) []byte {
isASCII, hasUpper := true, false
for i := 0; i < len(s); i++ {
c := s[i]
if c >= utf8.RuneSelf {
isASCII = false
break
}
hasUpper = hasUpper || ('A' <= c && c <= 'Z')
}
if isASCII { // optimize for ASCII-only byte slices.
if !hasUpper {
return append([]byte(""), s...)
}
b := make([]byte, len(s))
for i := 0; i < len(s); i++ {
c := s[i]
if 'A' <= c && c <= 'Z' {
c += 'a' - 'A'
}
b[i] = c
}
return b
}
return Map(unicode.ToLower, s)
}
// ToTitle treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their title case. // ToTitle treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their title case.
func ToTitle(s []byte) []byte { return Map(unicode.ToTitle, s) } func ToTitle(s []byte) []byte { return Map(unicode.ToTitle, s) }
@ -523,6 +592,35 @@ func ToTitleSpecial(c unicode.SpecialCase, s []byte) []byte {
return Map(c.ToTitle, s) return Map(c.ToTitle, s)
} }
// ToValidUTF8 treats s as UTF-8-encoded bytes and returns a copy with each run of bytes
// representing invalid UTF-8 replaced with the bytes in replacement, which may be empty.
func ToValidUTF8(s, replacement []byte) []byte {
b := make([]byte, 0, len(s)+len(replacement))
invalid := false // previous byte was from an invalid UTF-8 sequence
for i := 0; i < len(s); {
c := s[i]
if c < utf8.RuneSelf {
i++
invalid = false
b = append(b, byte(c))
continue
}
_, wid := utf8.DecodeRune(s[i:])
if wid == 1 {
i++
if !invalid {
invalid = true
b = append(b, replacement...)
}
continue
}
invalid = false
b = append(b, s[i:i+wid]...)
i += wid
}
return b
}
// isSeparator reports whether the rune could mark a word boundary. // isSeparator reports whether the rune could mark a word boundary.
// TODO: update when package unicode captures more of the properties. // TODO: update when package unicode captures more of the properties.
func isSeparator(r rune) bool { func isSeparator(r rune) bool {
@ -734,7 +832,41 @@ func TrimRight(s []byte, cutset string) []byte {
// TrimSpace returns a subslice of s by slicing off all leading and // TrimSpace returns a subslice of s by slicing off all leading and
// trailing white space, as defined by Unicode. // trailing white space, as defined by Unicode.
func TrimSpace(s []byte) []byte { func TrimSpace(s []byte) []byte {
return TrimFunc(s, unicode.IsSpace) // Fast path for ASCII: look for the first ASCII non-space byte
start := 0
for ; start < len(s); start++ {
c := s[start]
if c >= utf8.RuneSelf {
// If we run into a non-ASCII byte, fall back to the
// slower unicode-aware method on the remaining bytes
return TrimFunc(s[start:], unicode.IsSpace)
}
if asciiSpace[c] == 0 {
break
}
}
// Now look for the first ASCII non-space byte from the end
stop := len(s)
for ; stop > start; stop-- {
c := s[stop-1]
if c >= utf8.RuneSelf {
return TrimFunc(s[start:stop], unicode.IsSpace)
}
if asciiSpace[c] == 0 {
break
}
}
// At this point s[start:stop] starts and ends with an ASCII
// non-space bytes, so we're done. Non-ASCII cases have already
// been handled above.
if start == stop {
// Special case to preserve previous TrimLeftFunc behavior,
// returning nil instead of empty slice if all spaces.
return nil
}
return s[start:stop]
} }
// Runes interprets s as a sequence of UTF-8-encoded code points. // Runes interprets s as a sequence of UTF-8-encoded code points.
@ -987,3 +1119,20 @@ func hashStr(sep []byte) (uint32, uint32) {
} }
return hash, pow return hash, pow
} }
// hashStrRev returns the hash of the reverse of sep and the
// appropriate multiplicative factor for use in Rabin-Karp algorithm.
func hashStrRev(sep []byte) (uint32, uint32) {
hash := uint32(0)
for i := len(sep) - 1; i >= 0; i-- {
hash = hash*primeRK + uint32(sep[i])
}
var pow, sq uint32 = 1, primeRK
for i := len(sep); i > 0; i >>= 1 {
if i&1 != 0 {
pow *= sq
}
sq *= sq
}
return hash, pow
}

View file

@ -51,15 +51,17 @@ type BinOpTest struct {
} }
func TestEqual(t *testing.T) { func TestEqual(t *testing.T) {
for _, tt := range compareTests { // Run the tests and check for allocation at the same time.
eql := Equal(tt.a, tt.b) allocs := testing.AllocsPerRun(10, func() {
if eql != (tt.i == 0) { for _, tt := range compareTests {
t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql) eql := Equal(tt.a, tt.b)
} if eql != (tt.i == 0) {
eql = EqualPortable(tt.a, tt.b) t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql)
if eql != (tt.i == 0) { }
t.Errorf(`EqualPortable(%q, %q) = %v`, tt.a, tt.b, eql)
} }
})
if allocs > 0 {
t.Errorf("Equal allocated %v times", allocs)
} }
} }
@ -572,11 +574,6 @@ func BenchmarkEqual(b *testing.B) {
benchBytes(b, sizes, bmEqual(Equal)) benchBytes(b, sizes, bmEqual(Equal))
} }
func BenchmarkEqualPort(b *testing.B) {
sizes := []int{1, 6, 32, 4 << 10, 4 << 20, 64 << 20}
benchBytes(b, sizes, bmEqual(EqualPortable))
}
func bmEqual(equal func([]byte, []byte) bool) func(b *testing.B, n int) { func bmEqual(equal func([]byte, []byte) bool) func(b *testing.B, n int) {
return func(b *testing.B, n int) { return func(b *testing.B, n int) {
if len(bmbuf) < 2*n { if len(bmbuf) < 2*n {
@ -677,34 +674,6 @@ func BenchmarkCountSingle(b *testing.B) {
}) })
} }
type ExplodeTest struct {
s string
n int
a []string
}
var explodetests = []ExplodeTest{
{"", -1, []string{}},
{abcd, -1, []string{"a", "b", "c", "d"}},
{faces, -1, []string{"☺", "☻", "☹"}},
{abcd, 2, []string{"a", "bcd"}},
}
func TestExplode(t *testing.T) {
for _, tt := range explodetests {
a := SplitN([]byte(tt.s), nil, tt.n)
result := sliceOfString(a)
if !eq(result, tt.a) {
t.Errorf(`Explode("%s", %d) = %v; want %v`, tt.s, tt.n, result, tt.a)
continue
}
s := Join(a, []byte{})
if string(s) != tt.s {
t.Errorf(`Join(Explode("%s", %d), "") = "%s"`, tt.s, tt.n, s)
}
}
}
type SplitTest struct { type SplitTest struct {
s string s string
sep string sep string
@ -713,7 +682,9 @@ type SplitTest struct {
} }
var splittests = []SplitTest{ var splittests = []SplitTest{
{"", "", -1, []string{}},
{abcd, "a", 0, nil}, {abcd, "a", 0, nil},
{abcd, "", 2, []string{"a", "bcd"}},
{abcd, "a", -1, []string{"", "bcd"}}, {abcd, "a", -1, []string{"", "bcd"}},
{abcd, "z", -1, []string{"abcd"}}, {abcd, "z", -1, []string{"abcd"}},
{abcd, "", -1, []string{"a", "b", "c", "d"}}, {abcd, "", -1, []string{"a", "b", "c", "d"}},
@ -743,7 +714,7 @@ func TestSplit(t *testing.T) {
t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a) t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
continue continue
} }
if tt.n == 0 { if tt.n == 0 || len(a) == 0 {
continue continue
} }
@ -909,54 +880,72 @@ func TestFieldsFunc(t *testing.T) {
} }
// Test case for any function which accepts and returns a byte slice. // Test case for any function which accepts and returns a byte slice.
// For ease of creation, we write the byte slices as strings. // For ease of creation, we write the input byte slice as a string.
type StringTest struct { type StringTest struct {
in, out string in string
out []byte
} }
var upperTests = []StringTest{ var upperTests = []StringTest{
{"", ""}, {"", []byte("")},
{"abc", "ABC"}, {"ONLYUPPER", []byte("ONLYUPPER")},
{"AbC123", "ABC123"}, {"abc", []byte("ABC")},
{"azAZ09_", "AZAZ09_"}, {"AbC123", []byte("ABC123")},
{"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char {"azAZ09_", []byte("AZAZ09_")},
{"longStrinGwitHmixofsmaLLandcAps", []byte("LONGSTRINGWITHMIXOFSMALLANDCAPS")},
{"long\u0250string\u0250with\u0250nonascii\u2C6Fchars", []byte("LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS")},
{"\u0250\u0250\u0250\u0250\u0250", []byte("\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F")}, // grows one byte per char
{"a\u0080\U0010FFFF", []byte("A\u0080\U0010FFFF")}, // test utf8.RuneSelf and utf8.MaxRune
} }
var lowerTests = []StringTest{ var lowerTests = []StringTest{
{"", ""}, {"", []byte("")},
{"abc", "abc"}, {"abc", []byte("abc")},
{"AbC123", "abc123"}, {"AbC123", []byte("abc123")},
{"azAZ09_", "azaz09_"}, {"azAZ09_", []byte("azaz09_")},
{"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char {"longStrinGwitHmixofsmaLLandcAps", []byte("longstringwithmixofsmallandcaps")},
{"LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS", []byte("long\u0250string\u0250with\u0250nonascii\u0250chars")},
{"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", []byte("\u0251\u0251\u0251\u0251\u0251")}, // shrinks one byte per char
{"A\u0080\U0010FFFF", []byte("a\u0080\U0010FFFF")}, // test utf8.RuneSelf and utf8.MaxRune
} }
const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000" const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
var trimSpaceTests = []StringTest{ var trimSpaceTests = []StringTest{
{"", ""}, {"", nil},
{"abc", "abc"}, {" a", []byte("a")},
{space + "abc" + space, "abc"}, {"b ", []byte("b")},
{" ", ""}, {"abc", []byte("abc")},
{" \t\r\n \t\t\r\r\n\n ", ""}, {space + "abc" + space, []byte("abc")},
{" \t\r\n x\t\t\r\r\n\n ", "x"}, {" ", nil},
{" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"}, {"\u3000 ", nil},
{"1 \t\r\n2", "1 \t\r\n2"}, {" \u3000", nil},
{" x\x80", "x\x80"}, {" \t\r\n \t\t\r\r\n\n ", nil},
{" x\xc0", "x\xc0"}, {" \t\r\n x\t\t\r\r\n\n ", []byte("x")},
{"x \xc0\xc0 ", "x \xc0\xc0"}, {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", []byte("x\t\t\r\r\ny")},
{"x \xc0", "x \xc0"}, {"1 \t\r\n2", []byte("1 \t\r\n2")},
{"x \xc0 ", "x \xc0"}, {" x\x80", []byte("x\x80")},
{"x \xc0\xc0 ", "x \xc0\xc0"}, {" x\xc0", []byte("x\xc0")},
{"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"}, {"x \xc0\xc0 ", []byte("x \xc0\xc0")},
{"x ☺ ", "x ☺"}, {"x \xc0", []byte("x \xc0")},
{"x \xc0 ", []byte("x \xc0")},
{"x \xc0\xc0 ", []byte("x \xc0\xc0")},
{"x ☺\xc0\xc0 ", []byte("x ☺\xc0\xc0")},
{"x ☺ ", []byte("x ☺")},
} }
// Execute f on each test case. funcName should be the name of f; it's used // Execute f on each test case. funcName should be the name of f; it's used
// in failure reports. // in failure reports.
func runStringTests(t *testing.T, f func([]byte) []byte, funcName string, testCases []StringTest) { func runStringTests(t *testing.T, f func([]byte) []byte, funcName string, testCases []StringTest) {
for _, tc := range testCases { for _, tc := range testCases {
actual := string(f([]byte(tc.in))) actual := f([]byte(tc.in))
if actual != tc.out { if actual == nil && tc.out != nil {
t.Errorf("%s(%q) = nil; want %q", funcName, tc.in, tc.out)
}
if actual != nil && tc.out == nil {
t.Errorf("%s(%q) = %q; want nil", funcName, tc.in, actual)
}
if !Equal(actual, tc.out) {
t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out) t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out)
} }
} }
@ -1044,6 +1033,64 @@ func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTest
func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) } func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) }
func BenchmarkToUpper(b *testing.B) {
for _, tc := range upperTests {
tin := []byte(tc.in)
b.Run(tc.in, func(b *testing.B) {
for i := 0; i < b.N; i++ {
actual := ToUpper(tin)
if !Equal(actual, tc.out) {
b.Errorf("ToUpper(%q) = %q; want %q", tc.in, actual, tc.out)
}
}
})
}
}
func BenchmarkToLower(b *testing.B) {
for _, tc := range lowerTests {
tin := []byte(tc.in)
b.Run(tc.in, func(b *testing.B) {
for i := 0; i < b.N; i++ {
actual := ToLower(tin)
if !Equal(actual, tc.out) {
b.Errorf("ToLower(%q) = %q; want %q", tc.in, actual, tc.out)
}
}
})
}
}
var toValidUTF8Tests = []struct {
in string
repl string
out string
}{
{"", "\uFFFD", ""},
{"abc", "\uFFFD", "abc"},
{"\uFDDD", "\uFFFD", "\uFDDD"},
{"a\xffb", "\uFFFD", "a\uFFFDb"},
{"a\xffb\uFFFD", "X", "aXb\uFFFD"},
{"a☺\xffb☺\xC0\xAFc☺\xff", "", "a☺b☺c☺"},
{"a☺\xffb☺\xC0\xAFc☺\xff", "日本語", "a☺日本語b☺日本語c☺日本語"},
{"\xC0\xAF", "\uFFFD", "\uFFFD"},
{"\xE0\x80\xAF", "\uFFFD", "\uFFFD"},
{"\xed\xa0\x80", "abc", "abc"},
{"\xed\xbf\xbf", "\uFFFD", "\uFFFD"},
{"\xF0\x80\x80\xaf", "☺", "☺"},
{"\xF8\x80\x80\x80\xAF", "\uFFFD", "\uFFFD"},
{"\xFC\x80\x80\x80\x80\xAF", "\uFFFD", "\uFFFD"},
}
func TestToValidUTF8(t *testing.T) {
for _, tc := range toValidUTF8Tests {
got := ToValidUTF8([]byte(tc.in), []byte(tc.repl))
if !Equal(got, []byte(tc.out)) {
t.Errorf("ToValidUTF8(%q, %q) = %q; want %q", tc.in, tc.repl, got, tc.out)
}
}
}
func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) } func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) }
type RepeatTest struct { type RepeatTest struct {
@ -1250,8 +1297,11 @@ var isValidRune = predicate{
} }
type TrimFuncTest struct { type TrimFuncTest struct {
f predicate f predicate
in, out string in string
trimOut []byte
leftOut []byte
rightOut []byte
} }
func not(p predicate) predicate { func not(p predicate) predicate {
@ -1264,20 +1314,68 @@ func not(p predicate) predicate {
} }
var trimFuncTests = []TrimFuncTest{ var trimFuncTests = []TrimFuncTest{
{isSpace, space + " hello " + space, "hello"}, {isSpace, space + " hello " + space,
{isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"}, []byte("hello"),
{isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"}, []byte("hello " + space),
{not(isSpace), "hello" + space + "hello", space}, []byte(space + " hello")},
{not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"}, {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51",
{isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"}, []byte("hello"),
{not(isValidRune), "\xc0a\xc0", "a"}, []byte("hello34\u0e50\u0e51"),
[]byte("\u0e50\u0e5212hello")},
{isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F",
[]byte("hello"),
[]byte("helloEF\u2C6F\u2C6FGH\u2C6F\u2C6F"),
[]byte("\u2C6F\u2C6F\u2C6F\u2C6FABCDhello")},
{not(isSpace), "hello" + space + "hello",
[]byte(space),
[]byte(space + "hello"),
[]byte("hello" + space)},
{not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo",
[]byte("\u0e50\u0e521234\u0e50\u0e51"),
[]byte("\u0e50\u0e521234\u0e50\u0e51helo"),
[]byte("hello\u0e50\u0e521234\u0e50\u0e51")},
{isValidRune, "ab\xc0a\xc0cd",
[]byte("\xc0a\xc0"),
[]byte("\xc0a\xc0cd"),
[]byte("ab\xc0a\xc0")},
{not(isValidRune), "\xc0a\xc0",
[]byte("a"),
[]byte("a\xc0"),
[]byte("\xc0a")},
// The nils returned by TrimLeftFunc are odd behavior, but we need
// to preserve backwards compatibility.
{isSpace, "",
nil,
nil,
[]byte("")},
{isSpace, " ",
nil,
nil,
[]byte("")},
} }
func TestTrimFunc(t *testing.T) { func TestTrimFunc(t *testing.T) {
for _, tc := range trimFuncTests { for _, tc := range trimFuncTests {
actual := string(TrimFunc([]byte(tc.in), tc.f.f)) trimmers := []struct {
if actual != tc.out { name string
t.Errorf("TrimFunc(%q, %q) = %q; want %q", tc.in, tc.f.name, actual, tc.out) trim func(s []byte, f func(r rune) bool) []byte
out []byte
}{
{"TrimFunc", TrimFunc, tc.trimOut},
{"TrimLeftFunc", TrimLeftFunc, tc.leftOut},
{"TrimRightFunc", TrimRightFunc, tc.rightOut},
}
for _, trimmer := range trimmers {
actual := trimmer.trim([]byte(tc.in), tc.f.f)
if actual == nil && trimmer.out != nil {
t.Errorf("%s(%q, %q) = nil; want %q", trimmer.name, tc.in, tc.f.name, trimmer.out)
}
if actual != nil && trimmer.out == nil {
t.Errorf("%s(%q, %q) = %q; want nil", trimmer.name, tc.in, tc.f.name, actual)
}
if !Equal(actual, trimmer.out) {
t.Errorf("%s(%q, %q) = %q; want %q", trimmer.name, tc.in, tc.f.name, actual, trimmer.out)
}
} }
} }
} }
@ -1617,9 +1715,41 @@ func BenchmarkFieldsFunc(b *testing.B) {
} }
func BenchmarkTrimSpace(b *testing.B) { func BenchmarkTrimSpace(b *testing.B) {
s := []byte(" Some text. \n") tests := []struct {
for i := 0; i < b.N; i++ { name string
TrimSpace(s) input []byte
}{
{"NoTrim", []byte("typical")},
{"ASCII", []byte(" foo bar ")},
{"SomeNonASCII", []byte(" \u2000\t\r\n x\t\t\r\r\ny\n \u3000 ")},
{"JustNonASCII", []byte("\u2000\u2000\u2000☺☺☺☺\u3000\u3000\u3000")},
}
for _, test := range tests {
b.Run(test.name, func(b *testing.B) {
for i := 0; i < b.N; i++ {
TrimSpace(test.input)
}
})
}
}
func BenchmarkToValidUTF8(b *testing.B) {
tests := []struct {
name string
input []byte
}{
{"Valid", []byte("typical")},
{"InvalidASCII", []byte("foo\xffbar")},
{"InvalidNonASCII", []byte("日本語\xff日本語")},
}
replacement := []byte("\uFFFD")
b.ResetTimer()
for _, test := range tests {
b.Run(test.name, func(b *testing.B) {
for i := 0; i < b.N; i++ {
ToValidUTF8(test.input, replacement)
}
})
} }
} }
@ -1642,6 +1772,39 @@ func makeBenchInputHard() []byte {
var benchInputHard = makeBenchInputHard() var benchInputHard = makeBenchInputHard()
func benchmarkIndexHard(b *testing.B, sep []byte) {
for i := 0; i < b.N; i++ {
Index(benchInputHard, sep)
}
}
func benchmarkLastIndexHard(b *testing.B, sep []byte) {
for i := 0; i < b.N; i++ {
LastIndex(benchInputHard, sep)
}
}
func benchmarkCountHard(b *testing.B, sep []byte) {
for i := 0; i < b.N; i++ {
Count(benchInputHard, sep)
}
}
func BenchmarkIndexHard1(b *testing.B) { benchmarkIndexHard(b, []byte("<>")) }
func BenchmarkIndexHard2(b *testing.B) { benchmarkIndexHard(b, []byte("</pre>")) }
func BenchmarkIndexHard3(b *testing.B) { benchmarkIndexHard(b, []byte("<b>hello world</b>")) }
func BenchmarkIndexHard4(b *testing.B) {
benchmarkIndexHard(b, []byte("<pre><b>hello</b><strong>world</strong></pre>"))
}
func BenchmarkLastIndexHard1(b *testing.B) { benchmarkLastIndexHard(b, []byte("<>")) }
func BenchmarkLastIndexHard2(b *testing.B) { benchmarkLastIndexHard(b, []byte("</pre>")) }
func BenchmarkLastIndexHard3(b *testing.B) { benchmarkLastIndexHard(b, []byte("<b>hello world</b>")) }
func BenchmarkCountHard1(b *testing.B) { benchmarkCountHard(b, []byte("<>")) }
func BenchmarkCountHard2(b *testing.B) { benchmarkCountHard(b, []byte("</pre>")) }
func BenchmarkCountHard3(b *testing.B) { benchmarkCountHard(b, []byte("<b>hello world</b>")) }
func BenchmarkSplitEmptySeparator(b *testing.B) { func BenchmarkSplitEmptySeparator(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
Split(benchInputHard, nil) Split(benchInputHard, nil)

View file

@ -365,6 +365,16 @@ func ExampleToTitle() {
// ХЛЕБ // ХЛЕБ
} }
func ExampleToTitleSpecial() {
str := []byte("ahoj vývojári golang")
totitle := bytes.ToTitleSpecial(unicode.AzeriCase, str)
fmt.Println("Original : " + string(str))
fmt.Println("ToTitle : " + string(totitle))
// Output:
// Original : ahoj vývojári golang
// ToTitle : AHOJ VÝVOJÁRİ GOLANG
}
func ExampleTrim() { func ExampleTrim() {
fmt.Printf("[%q]", bytes.Trim([]byte(" !!! Achtung! Achtung! !!! "), "! ")) fmt.Printf("[%q]", bytes.Trim([]byte(" !!! Achtung! Achtung! !!! "), "! "))
// Output: ["Achtung! Achtung"] // Output: ["Achtung! Achtung"]
@ -438,11 +448,31 @@ func ExampleToUpper() {
// Output: GOPHER // Output: GOPHER
} }
func ExampleToUpperSpecial() {
str := []byte("ahoj vývojári golang")
totitle := bytes.ToUpperSpecial(unicode.AzeriCase, str)
fmt.Println("Original : " + string(str))
fmt.Println("ToUpper : " + string(totitle))
// Output:
// Original : ahoj vývojári golang
// ToUpper : AHOJ VÝVOJÁRİ GOLANG
}
func ExampleToLower() { func ExampleToLower() {
fmt.Printf("%s", bytes.ToLower([]byte("Gopher"))) fmt.Printf("%s", bytes.ToLower([]byte("Gopher")))
// Output: gopher // Output: gopher
} }
func ExampleToLowerSpecial() {
str := []byte("AHOJ VÝVOJÁRİ GOLANG")
totitle := bytes.ToLowerSpecial(unicode.AzeriCase, str)
fmt.Println("Original : " + string(str))
fmt.Println("ToLower : " + string(totitle))
// Output:
// Original : AHOJ VÝVOJÁRİ GOLANG
// ToLower : ahoj vývojári golang
}
func ExampleReader_Len() { func ExampleReader_Len() {
fmt.Println(bytes.NewReader([]byte("Hi!")).Len()) fmt.Println(bytes.NewReader([]byte("Hi!")).Len())
fmt.Println(bytes.NewReader([]byte("こんにちは!")).Len()) fmt.Println(bytes.NewReader([]byte("こんにちは!")).Len())

View file

@ -6,4 +6,3 @@ package bytes
// Export func for testing // Export func for testing
var IndexBytePortable = indexBytePortable var IndexBytePortable = indexBytePortable
var EqualPortable = equalPortable

2
src/cmd/README.vendor Normal file
View file

@ -0,0 +1,2 @@
See src/README.vendor for information on loading vendored packages
and updating the vendor directory.

View file

@ -8,6 +8,7 @@ package main
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"encoding/json"
"flag" "flag"
"fmt" "fmt"
"go/ast" "go/ast"
@ -76,6 +77,8 @@ var contexts = []*build.Context{
{GOOS: "netbsd", GOARCH: "amd64"}, {GOOS: "netbsd", GOARCH: "amd64"},
{GOOS: "netbsd", GOARCH: "arm", CgoEnabled: true}, {GOOS: "netbsd", GOARCH: "arm", CgoEnabled: true},
{GOOS: "netbsd", GOARCH: "arm"}, {GOOS: "netbsd", GOARCH: "arm"},
{GOOS: "netbsd", GOARCH: "arm64", CgoEnabled: true},
{GOOS: "netbsd", GOARCH: "arm64"},
{GOOS: "openbsd", GOARCH: "386", CgoEnabled: true}, {GOOS: "openbsd", GOARCH: "386", CgoEnabled: true},
{GOOS: "openbsd", GOARCH: "386"}, {GOOS: "openbsd", GOARCH: "386"},
{GOOS: "openbsd", GOARCH: "amd64", CgoEnabled: true}, {GOOS: "openbsd", GOARCH: "amd64", CgoEnabled: true},
@ -153,6 +156,7 @@ func main() {
var featureCtx = make(map[string]map[string]bool) // feature -> context name -> true var featureCtx = make(map[string]map[string]bool) // feature -> context name -> true
for _, context := range contexts { for _, context := range contexts {
w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src")) w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
w.loadImports(pkgNames, w.context)
for _, name := range pkgNames { for _, name := range pkgNames {
// Vendored packages do not contribute to our // Vendored packages do not contribute to our
@ -169,7 +173,13 @@ func main() {
// w.Import(name) will return nil // w.Import(name) will return nil
continue continue
} }
pkg, _ := w.Import(name) pkg, err := w.Import(name)
if _, nogo := err.(*build.NoGoError); nogo {
continue
}
if err != nil {
log.Fatalf("Import(%q): %v", name, err)
}
w.export(pkg) w.export(pkg)
} }
} }
@ -233,7 +243,7 @@ func (w *Walker) export(pkg *types.Package) {
w.current = pkg w.current = pkg
scope := pkg.Scope() scope := pkg.Scope()
for _, name := range scope.Names() { for _, name := range scope.Names() {
if ast.IsExported(name) { if token.IsExported(name) {
w.emitObj(scope.Lookup(name)) w.emitObj(scope.Lookup(name))
} }
} }
@ -343,12 +353,14 @@ func fileFeatures(filename string) []string {
var fset = token.NewFileSet() var fset = token.NewFileSet()
type Walker struct { type Walker struct {
context *build.Context context *build.Context
root string root string
scope []string scope []string
current *types.Package current *types.Package
features map[string]bool // set features map[string]bool // set
imported map[string]*types.Package // packages already imported imported map[string]*types.Package // packages already imported
importMap map[string]map[string]string // importer dir -> import path -> canonical path
importDir map[string]string // canonical import path -> dir
} }
func NewWalker(context *build.Context, root string) *Walker { func NewWalker(context *build.Context, root string) *Walker {
@ -428,11 +440,74 @@ func tagKey(dir string, context *build.Context, tags []string) string {
return key return key
} }
func (w *Walker) loadImports(paths []string, context *build.Context) {
if context == nil {
context = &build.Default
}
var (
tags = context.BuildTags
cgoEnabled = "0"
)
if context.CgoEnabled {
tags = append(tags[:len(tags):len(tags)], "cgo")
cgoEnabled = "1"
}
// TODO(golang.org/issue/29666): Request only the fields that we need.
cmd := exec.Command(goCmd(), "list", "-e", "-deps", "-json")
if len(tags) > 0 {
cmd.Args = append(cmd.Args, "-tags", strings.Join(tags, " "))
}
cmd.Args = append(cmd.Args, paths...)
cmd.Env = append(os.Environ(),
"GOOS="+context.GOOS,
"GOARCH="+context.GOARCH,
"CGO_ENABLED="+cgoEnabled,
)
stdout := new(bytes.Buffer)
cmd.Stdout = stdout
cmd.Stderr = new(strings.Builder)
err := cmd.Run()
if err != nil {
log.Fatalf("%s failed: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr)
}
w.importDir = make(map[string]string)
w.importMap = make(map[string]map[string]string)
dec := json.NewDecoder(stdout)
for {
var pkg struct {
ImportPath, Dir string
ImportMap map[string]string
}
if err := dec.Decode(&pkg); err == io.EOF {
break
} else if err != nil {
log.Fatalf("%s: invalid output: %v", strings.Join(cmd.Args, " "), err)
}
w.importDir[pkg.ImportPath] = pkg.Dir
w.importMap[pkg.Dir] = pkg.ImportMap
}
}
// Importing is a sentinel taking the place in Walker.imported // Importing is a sentinel taking the place in Walker.imported
// for a package that is in the process of being imported. // for a package that is in the process of being imported.
var importing types.Package var importing types.Package
func (w *Walker) Import(name string) (*types.Package, error) { func (w *Walker) Import(name string) (*types.Package, error) {
return w.ImportFrom(name, "", 0)
}
func (w *Walker) ImportFrom(fromPath, fromDir string, mode types.ImportMode) (*types.Package, error) {
name := fromPath
if canonical, ok := w.importMap[fromDir][fromPath]; ok {
name = canonical
}
pkg := w.imported[name] pkg := w.imported[name]
if pkg != nil { if pkg != nil {
if pkg == &importing { if pkg == &importing {
@ -443,7 +518,10 @@ func (w *Walker) Import(name string) (*types.Package, error) {
w.imported[name] = &importing w.imported[name] = &importing
// Determine package files. // Determine package files.
dir := filepath.Join(w.root, filepath.FromSlash(name)) dir := w.importDir[name]
if dir == "" {
dir = filepath.Join(w.root, filepath.FromSlash(name))
}
if fi, err := os.Stat(dir); err != nil || !fi.IsDir() { if fi, err := os.Stat(dir); err != nil || !fi.IsDir() {
log.Fatalf("no source in tree for import %q: %v", name, err) log.Fatalf("no source in tree for import %q: %v", name, err)
} }
@ -470,7 +548,7 @@ func (w *Walker) Import(name string) (*types.Package, error) {
info, err := context.ImportDir(dir, 0) info, err := context.ImportDir(dir, 0)
if err != nil { if err != nil {
if _, nogo := err.(*build.NoGoError); nogo { if _, nogo := err.(*build.NoGoError); nogo {
return nil, nil return nil, err
} }
log.Fatalf("pkg %q, dir %q: ScanDir: %v", name, dir, err) log.Fatalf("pkg %q, dir %q: ScanDir: %v", name, dir, err)
} }

View file

@ -203,3 +203,16 @@ func TestIssue21181(t *testing.T) {
w.export(pkg) w.export(pkg)
} }
} }
func TestIssue29837(t *testing.T) {
for _, c := range contexts {
c.Compiler = build.Default.Compiler
}
for _, context := range contexts {
w := NewWalker(context, "testdata/src/issue29837")
_, err := w.Import("p")
if _, nogo := err.(*build.NoGoError); !nogo {
t.Errorf("expected *build.NoGoError, got %T", err)
}
}
}

View file

@ -0,0 +1 @@
Empty directory for test, see https://golang.org/issues/29837.

View file

@ -72,14 +72,11 @@ func IsARM64STLXR(op obj.As) bool {
switch op { switch op {
case arm64.ASTLXRB, arm64.ASTLXRH, arm64.ASTLXRW, arm64.ASTLXR, case arm64.ASTLXRB, arm64.ASTLXRH, arm64.ASTLXRW, arm64.ASTLXR,
arm64.ASTXRB, arm64.ASTXRH, arm64.ASTXRW, arm64.ASTXR, arm64.ASTXRB, arm64.ASTXRH, arm64.ASTXRW, arm64.ASTXR,
arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW, arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW:
arm64.ASWPB, arm64.ASWPH, arm64.ASWPW, arm64.ASWPD, return true
arm64.ASWPALB, arm64.ASWPALH, arm64.ASWPALW, arm64.ASWPALD, }
arm64.ALDADDB, arm64.ALDADDH, arm64.ALDADDW, arm64.ALDADDD, // atomic instructions
arm64.ALDANDB, arm64.ALDANDH, arm64.ALDANDW, arm64.ALDANDD, if arm64.IsAtomicInstruction(op) {
arm64.ALDEORB, arm64.ALDEORH, arm64.ALDEORW, arm64.ALDEORD,
arm64.ALDORB, arm64.ALDORH, arm64.ALDORW, arm64.ALDORD,
arm64.ALDADDALD, arm64.ALDADDALW, arm64.ALDADDALH, arm64.ALDADDALB:
return true return true
} }
return false return false

View file

@ -33,12 +33,13 @@ func IsMIPSCMP(op obj.As) bool {
} }
// IsMIPSMUL reports whether the op (as defined by an mips.A* constant) is // IsMIPSMUL reports whether the op (as defined by an mips.A* constant) is
// one of the MUL/DIV/REM instructions that require special handling. // one of the MUL/DIV/REM/MADD/MSUB instructions that require special handling.
func IsMIPSMUL(op obj.As) bool { func IsMIPSMUL(op obj.As) bool {
switch op { switch op {
case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU, case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU,
mips.ADIV, mips.ADIVU, mips.ADIVV, mips.ADIVVU, mips.ADIV, mips.ADIVU, mips.ADIVV, mips.ADIVVU,
mips.AREM, mips.AREMU, mips.AREMV, mips.AREMVU: mips.AREM, mips.AREMU, mips.AREMV, mips.AREMVU,
mips.AMADD, mips.AMSUB:
return true return true
} }
return false return false

View file

@ -789,6 +789,12 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.To = a[4] prog.To = a[4]
break break
} }
if p.arch.Family == sys.S390X {
prog.From = a[0]
prog.RestArgs = []obj.Addr{a[1], a[2], a[3]}
prog.To = a[4]
break
}
p.errorf("can't handle %s instruction with 5 operands", op) p.errorf("can't handle %s instruction with 5 operands", op)
return return
case 6: case 6:

View file

@ -28,6 +28,10 @@ func TestAMD64BadInstParser(t *testing.T) {
{"VADDPD.BCST.Z.SAE X0, X1, X2", `Z suffix should be the last; can't combine rounding/SAE and broadcast`}, {"VADDPD.BCST.Z.SAE X0, X1, X2", `Z suffix should be the last; can't combine rounding/SAE and broadcast`},
{"VADDPD.SAE.SAE X0, X1, X2", `duplicate suffix "SAE"`}, {"VADDPD.SAE.SAE X0, X1, X2", `duplicate suffix "SAE"`},
{"VADDPD.RZ_SAE.SAE X0, X1, X2", `bad suffix combination`}, {"VADDPD.RZ_SAE.SAE X0, X1, X2", `bad suffix combination`},
// BSWAP on 16-bit registers is undefined. See #29167,
{"BSWAPW DX", `unrecognized instruction`},
{"BSWAPW R11", `unrecognized instruction`},
}) })
} }

View file

@ -145,17 +145,18 @@ func TestFuncAddress(t *testing.T) {
isFuncSym := strings.HasSuffix(test.input, "(SB)") && isFuncSym := strings.HasSuffix(test.input, "(SB)") &&
// Ignore static symbols. // Ignore static symbols.
!strings.Contains(test.input, "<>") && !strings.Contains(test.input, "<>")
// Ignore symbols with offsets.
!strings.Contains(test.input, "+")
wantName := "" wantName := ""
if isFuncSym { if isFuncSym {
// Strip $|* and (SB). // Strip $|* and (SB) and +Int.
wantName = test.output[:len(test.output)-4] wantName = test.output[:len(test.output)-4]
if strings.HasPrefix(wantName, "$") || strings.HasPrefix(wantName, "*") { if strings.HasPrefix(wantName, "$") || strings.HasPrefix(wantName, "*") {
wantName = wantName[1:] wantName = wantName[1:]
} }
if i := strings.Index(wantName, "+"); i >= 0 {
wantName = wantName[:i]
}
} }
if ok != isFuncSym || name != wantName { if ok != isFuncSym || name != wantName {
t.Errorf("fail at %s as function address: got %s, %v; expected %s, %v", test.input, name, ok, wantName, isFuncSym) t.Errorf("fail at %s as function address: got %s, %v; expected %s, %v", test.input, name, ok, wantName, isFuncSym)

View file

@ -800,9 +800,9 @@ func (p *Parser) setPseudoRegister(addr *obj.Addr, reg string, isStatic bool, pr
// funcAddress parses an external function address. This is a // funcAddress parses an external function address. This is a
// constrained form of the operand syntax that's always SB-based, // constrained form of the operand syntax that's always SB-based,
// non-static, and has no additional offsets: // non-static, and has at most a simple integer offset:
// //
// [$|*]sym(SB) // [$|*]sym[+Int](SB)
func (p *Parser) funcAddress() (string, bool) { func (p *Parser) funcAddress() (string, bool) {
switch p.peek() { switch p.peek() {
case '$', '*': case '$', '*':
@ -815,7 +815,14 @@ func (p *Parser) funcAddress() (string, bool) {
if tok.ScanToken != scanner.Ident || p.atStartOfRegister(name) { if tok.ScanToken != scanner.Ident || p.atStartOfRegister(name) {
return "", false return "", false
} }
if p.next().ScanToken != '(' { tok = p.next()
if tok.ScanToken == '+' {
if p.next().ScanToken != scanner.Int {
return "", false
}
tok = p.next()
}
if tok.ScanToken != '(' {
return "", false return "", false
} }
if reg := p.next(); reg.ScanToken != scanner.Ident || reg.String() != "SB" { if reg := p.next(); reg.ScanToken != scanner.Ident || reg.String() != "SB" {

View file

@ -89,6 +89,10 @@ label:
loop: loop:
LOOP loop // LOOP LOOP loop // LOOP
// Tests for TLS reference.
MOVL (TLS), AX
MOVL 8(TLS), DX
// LTYPE0 nonnon { outcode(int($1), &$2); } // LTYPE0 nonnon { outcode(int($1), &$2); }
RET RET
RET foo(SB) RET foo(SB)

View file

@ -143,6 +143,10 @@ loop:
MOVB foo+32(SP)(CX*4), AH // 8a648c20 MOVB foo+32(SP)(CX*4), AH // 8a648c20
MOVB foo+32323(SP)(CX*8), R9 // 448a8ccc437e0000 MOVB foo+32323(SP)(CX*8), R9 // 448a8ccc437e0000
// Tests for TLS reference.
MOVQ (TLS), AX
MOVQ 8(TLS), DX
// LTYPE0 nonnon { outcode($1, &$2); } // LTYPE0 nonnon { outcode($1, &$2); }
RET // c3 RET // c3
RET foo(SB) RET foo(SB)

View file

@ -588,8 +588,6 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
BSRQ (R11), R11 // 4d0fbd1b BSRQ (R11), R11 // 4d0fbd1b
BSRQ DX, R11 // 4c0fbdda BSRQ DX, R11 // 4c0fbdda
BSRQ R11, R11 // 4d0fbddb BSRQ R11, R11 // 4d0fbddb
BSWAPW DX // 660fca
BSWAPW R11 // 66410fcb
BSWAPL DX // 0fca BSWAPL DX // 0fca
BSWAPL R11 // 410fcb BSWAPL R11 // 410fcb
BSWAPQ DX // 480fca BSWAPQ DX // 480fca

View file

@ -659,14 +659,14 @@ again:
STXP (R1, R2), (RSP), R10 // e10b2ac8 STXP (R1, R2), (RSP), R10 // e10b2ac8
STXPW (R1, R2), (R3), R10 // 61082a88 STXPW (R1, R2), (R3), R10 // 61082a88
STXPW (R1, R2), (RSP), R10 // e10b2a88 STXPW (R1, R2), (RSP), R10 // e10b2a88
SWPD R5, (R6), R7 // c78025f8 SWPAD R5, (R6), R7 // c780a5f8
SWPD R5, (RSP), R7 // e78325f8 SWPAD R5, (RSP), R7 // e783a5f8
SWPW R5, (R6), R7 // c78025b8 SWPAW R5, (R6), R7 // c780a5b8
SWPW R5, (RSP), R7 // e78325b8 SWPAW R5, (RSP), R7 // e783a5b8
SWPH R5, (R6), R7 // c7802578 SWPAH R5, (R6), R7 // c780a578
SWPH R5, (RSP), R7 // e7832578 SWPAH R5, (RSP), R7 // e783a578
SWPB R5, (R6), R7 // c7802538 SWPAB R5, (R6), R7 // c780a538
SWPB R5, (RSP), R7 // e7832538 SWPAB R5, (RSP), R7 // e783a538
SWPALD R5, (R6), R7 // c780e5f8 SWPALD R5, (R6), R7 // c780e5f8
SWPALD R5, (RSP), R7 // e783e5f8 SWPALD R5, (RSP), R7 // e783e5f8
SWPALW R5, (R6), R7 // c780e5b8 SWPALW R5, (R6), R7 // c780e5b8
@ -675,6 +675,38 @@ again:
SWPALH R5, (RSP), R7 // e783e578 SWPALH R5, (RSP), R7 // e783e578
SWPALB R5, (R6), R7 // c780e538 SWPALB R5, (R6), R7 // c780e538
SWPALB R5, (RSP), R7 // e783e538 SWPALB R5, (RSP), R7 // e783e538
SWPD R5, (R6), R7 // c78025f8
SWPD R5, (RSP), R7 // e78325f8
SWPW R5, (R6), R7 // c78025b8
SWPW R5, (RSP), R7 // e78325b8
SWPH R5, (R6), R7 // c7802578
SWPH R5, (RSP), R7 // e7832578
SWPB R5, (R6), R7 // c7802538
SWPB R5, (RSP), R7 // e7832538
SWPLD R5, (R6), R7 // c78065f8
SWPLD R5, (RSP), R7 // e78365f8
SWPLW R5, (R6), R7 // c78065b8
SWPLW R5, (RSP), R7 // e78365b8
SWPLH R5, (R6), R7 // c7806578
SWPLH R5, (RSP), R7 // e7836578
SWPLB R5, (R6), R7 // c7806538
SWPLB R5, (RSP), R7 // e7836538
LDADDAD R5, (R6), R7 // c700a5f8
LDADDAD R5, (RSP), R7 // e703a5f8
LDADDAW R5, (R6), R7 // c700a5b8
LDADDAW R5, (RSP), R7 // e703a5b8
LDADDAH R5, (R6), R7 // c700a578
LDADDAH R5, (RSP), R7 // e703a578
LDADDAB R5, (R6), R7 // c700a538
LDADDAB R5, (RSP), R7 // e703a538
LDADDALD R5, (R6), R7 // c700e5f8
LDADDALD R5, (RSP), R7 // e703e5f8
LDADDALW R5, (R6), R7 // c700e5b8
LDADDALW R5, (RSP), R7 // e703e5b8
LDADDALH R5, (R6), R7 // c700e578
LDADDALH R5, (RSP), R7 // e703e578
LDADDALB R5, (R6), R7 // c700e538
LDADDALB R5, (RSP), R7 // e703e538
LDADDD R5, (R6), R7 // c70025f8 LDADDD R5, (R6), R7 // c70025f8
LDADDD R5, (RSP), R7 // e70325f8 LDADDD R5, (RSP), R7 // e70325f8
LDADDW R5, (R6), R7 // c70025b8 LDADDW R5, (R6), R7 // c70025b8
@ -683,6 +715,30 @@ again:
LDADDH R5, (RSP), R7 // e7032578 LDADDH R5, (RSP), R7 // e7032578
LDADDB R5, (R6), R7 // c7002538 LDADDB R5, (R6), R7 // c7002538
LDADDB R5, (RSP), R7 // e7032538 LDADDB R5, (RSP), R7 // e7032538
LDADDLD R5, (R6), R7 // c70065f8
LDADDLD R5, (RSP), R7 // e70365f8
LDADDLW R5, (R6), R7 // c70065b8
LDADDLW R5, (RSP), R7 // e70365b8
LDADDLH R5, (R6), R7 // c7006578
LDADDLH R5, (RSP), R7 // e7036578
LDADDLB R5, (R6), R7 // c7006538
LDADDLB R5, (RSP), R7 // e7036538
LDANDAD R5, (R6), R7 // c710a5f8
LDANDAD R5, (RSP), R7 // e713a5f8
LDANDAW R5, (R6), R7 // c710a5b8
LDANDAW R5, (RSP), R7 // e713a5b8
LDANDAH R5, (R6), R7 // c710a578
LDANDAH R5, (RSP), R7 // e713a578
LDANDAB R5, (R6), R7 // c710a538
LDANDAB R5, (RSP), R7 // e713a538
LDANDALD R5, (R6), R7 // c710e5f8
LDANDALD R5, (RSP), R7 // e713e5f8
LDANDALW R5, (R6), R7 // c710e5b8
LDANDALW R5, (RSP), R7 // e713e5b8
LDANDALH R5, (R6), R7 // c710e578
LDANDALH R5, (RSP), R7 // e713e578
LDANDALB R5, (R6), R7 // c710e538
LDANDALB R5, (RSP), R7 // e713e538
LDANDD R5, (R6), R7 // c71025f8 LDANDD R5, (R6), R7 // c71025f8
LDANDD R5, (RSP), R7 // e71325f8 LDANDD R5, (RSP), R7 // e71325f8
LDANDW R5, (R6), R7 // c71025b8 LDANDW R5, (R6), R7 // c71025b8
@ -691,6 +747,30 @@ again:
LDANDH R5, (RSP), R7 // e7132578 LDANDH R5, (RSP), R7 // e7132578
LDANDB R5, (R6), R7 // c7102538 LDANDB R5, (R6), R7 // c7102538
LDANDB R5, (RSP), R7 // e7132538 LDANDB R5, (RSP), R7 // e7132538
LDANDLD R5, (R6), R7 // c71065f8
LDANDLD R5, (RSP), R7 // e71365f8
LDANDLW R5, (R6), R7 // c71065b8
LDANDLW R5, (RSP), R7 // e71365b8
LDANDLH R5, (R6), R7 // c7106578
LDANDLH R5, (RSP), R7 // e7136578
LDANDLB R5, (R6), R7 // c7106538
LDANDLB R5, (RSP), R7 // e7136538
LDEORAD R5, (R6), R7 // c720a5f8
LDEORAD R5, (RSP), R7 // e723a5f8
LDEORAW R5, (R6), R7 // c720a5b8
LDEORAW R5, (RSP), R7 // e723a5b8
LDEORAH R5, (R6), R7 // c720a578
LDEORAH R5, (RSP), R7 // e723a578
LDEORAB R5, (R6), R7 // c720a538
LDEORAB R5, (RSP), R7 // e723a538
LDEORALD R5, (R6), R7 // c720e5f8
LDEORALD R5, (RSP), R7 // e723e5f8
LDEORALW R5, (R6), R7 // c720e5b8
LDEORALW R5, (RSP), R7 // e723e5b8
LDEORALH R5, (R6), R7 // c720e578
LDEORALH R5, (RSP), R7 // e723e578
LDEORALB R5, (R6), R7 // c720e538
LDEORALB R5, (RSP), R7 // e723e538
LDEORD R5, (R6), R7 // c72025f8 LDEORD R5, (R6), R7 // c72025f8
LDEORD R5, (RSP), R7 // e72325f8 LDEORD R5, (RSP), R7 // e72325f8
LDEORW R5, (R6), R7 // c72025b8 LDEORW R5, (R6), R7 // c72025b8
@ -699,6 +779,30 @@ again:
LDEORH R5, (RSP), R7 // e7232578 LDEORH R5, (RSP), R7 // e7232578
LDEORB R5, (R6), R7 // c7202538 LDEORB R5, (R6), R7 // c7202538
LDEORB R5, (RSP), R7 // e7232538 LDEORB R5, (RSP), R7 // e7232538
LDEORLD R5, (R6), R7 // c72065f8
LDEORLD R5, (RSP), R7 // e72365f8
LDEORLW R5, (R6), R7 // c72065b8
LDEORLW R5, (RSP), R7 // e72365b8
LDEORLH R5, (R6), R7 // c7206578
LDEORLH R5, (RSP), R7 // e7236578
LDEORLB R5, (R6), R7 // c7206538
LDEORLB R5, (RSP), R7 // e7236538
LDORAD R5, (R6), R7 // c730a5f8
LDORAD R5, (RSP), R7 // e733a5f8
LDORAW R5, (R6), R7 // c730a5b8
LDORAW R5, (RSP), R7 // e733a5b8
LDORAH R5, (R6), R7 // c730a578
LDORAH R5, (RSP), R7 // e733a578
LDORAB R5, (R6), R7 // c730a538
LDORAB R5, (RSP), R7 // e733a538
LDORALD R5, (R6), R7 // c730e5f8
LDORALD R5, (RSP), R7 // e733e5f8
LDORALW R5, (R6), R7 // c730e5b8
LDORALW R5, (RSP), R7 // e733e5b8
LDORALH R5, (R6), R7 // c730e578
LDORALH R5, (RSP), R7 // e733e578
LDORALB R5, (R6), R7 // c730e538
LDORALB R5, (RSP), R7 // e733e538
LDORD R5, (R6), R7 // c73025f8 LDORD R5, (R6), R7 // c73025f8
LDORD R5, (RSP), R7 // e73325f8 LDORD R5, (RSP), R7 // e73325f8
LDORW R5, (R6), R7 // c73025b8 LDORW R5, (R6), R7 // c73025b8
@ -707,11 +811,14 @@ again:
LDORH R5, (RSP), R7 // e7332578 LDORH R5, (RSP), R7 // e7332578
LDORB R5, (R6), R7 // c7302538 LDORB R5, (R6), R7 // c7302538
LDORB R5, (RSP), R7 // e7332538 LDORB R5, (RSP), R7 // e7332538
LDADDALD R2, (R1), R3 // 2300e2f8 LDORLD R5, (R6), R7 // c73065f8
LDADDALW R2, (R1), R3 // 2300e2b8 LDORLD R5, (RSP), R7 // e73365f8
LDADDALH R2, (R1), R3 // 2300e278 LDORLW R5, (R6), R7 // c73065b8
LDADDALB R2, (R1), R3 // 2300e238 LDORLW R5, (RSP), R7 // e73365b8
LDORLH R5, (R6), R7 // c7306578
LDORLH R5, (RSP), R7 // e7336578
LDORLB R5, (R6), R7 // c7306538
LDORLB R5, (RSP), R7 // e7336538
// RET // RET
// //
// LTYPEA comma // LTYPEA comma

View file

@ -112,4 +112,124 @@ TEXT errors(SB),$0
FSTPD (R1, R2), (R0) // ERROR "invalid register pair" FSTPD (R1, R2), (R0) // ERROR "invalid register pair"
FMOVS (F2), F0 // ERROR "illegal combination" FMOVS (F2), F0 // ERROR "illegal combination"
FMOVD F0, (F1) // ERROR "illegal combination" FMOVD F0, (F1) // ERROR "illegal combination"
LDADDD R5, (R6), ZR // ERROR "illegal destination register"
LDADDW R5, (R6), ZR // ERROR "illegal destination register"
LDADDH R5, (R6), ZR // ERROR "illegal destination register"
LDADDB R5, (R6), ZR // ERROR "illegal destination register"
LDADDLD R5, (R6), ZR // ERROR "illegal destination register"
LDADDLW R5, (R6), ZR // ERROR "illegal destination register"
LDADDLH R5, (R6), ZR // ERROR "illegal destination register"
LDADDLB R5, (R6), ZR // ERROR "illegal destination register"
LDANDD R5, (R6), ZR // ERROR "illegal destination register"
LDANDW R5, (R6), ZR // ERROR "illegal destination register"
LDANDH R5, (R6), ZR // ERROR "illegal destination register"
LDANDB R5, (R6), ZR // ERROR "illegal destination register"
LDANDLD R5, (R6), ZR // ERROR "illegal destination register"
LDANDLW R5, (R6), ZR // ERROR "illegal destination register"
LDANDLH R5, (R6), ZR // ERROR "illegal destination register"
LDANDLB R5, (R6), ZR // ERROR "illegal destination register"
LDEORD R5, (R6), ZR // ERROR "illegal destination register"
LDEORW R5, (R6), ZR // ERROR "illegal destination register"
LDEORH R5, (R6), ZR // ERROR "illegal destination register"
LDEORB R5, (R6), ZR // ERROR "illegal destination register"
LDEORLD R5, (R6), ZR // ERROR "illegal destination register"
LDEORLW R5, (R6), ZR // ERROR "illegal destination register"
LDEORLH R5, (R6), ZR // ERROR "illegal destination register"
LDEORLB R5, (R6), ZR // ERROR "illegal destination register"
LDORD R5, (R6), ZR // ERROR "illegal destination register"
LDORW R5, (R6), ZR // ERROR "illegal destination register"
LDORH R5, (R6), ZR // ERROR "illegal destination register"
LDORB R5, (R6), ZR // ERROR "illegal destination register"
LDORLD R5, (R6), ZR // ERROR "illegal destination register"
LDORLW R5, (R6), ZR // ERROR "illegal destination register"
LDORLH R5, (R6), ZR // ERROR "illegal destination register"
LDORLB R5, (R6), ZR // ERROR "illegal destination register"
LDADDAD R5, (R6), RSP // ERROR "illegal destination register"
LDADDAW R5, (R6), RSP // ERROR "illegal destination register"
LDADDAH R5, (R6), RSP // ERROR "illegal destination register"
LDADDAB R5, (R6), RSP // ERROR "illegal destination register"
LDADDALD R5, (R6), RSP // ERROR "illegal destination register"
LDADDALW R5, (R6), RSP // ERROR "illegal destination register"
LDADDALH R5, (R6), RSP // ERROR "illegal destination register"
LDADDALB R5, (R6), RSP // ERROR "illegal destination register"
LDADDD R5, (R6), RSP // ERROR "illegal destination register"
LDADDW R5, (R6), RSP // ERROR "illegal destination register"
LDADDH R5, (R6), RSP // ERROR "illegal destination register"
LDADDB R5, (R6), RSP // ERROR "illegal destination register"
LDADDLD R5, (R6), RSP // ERROR "illegal destination register"
LDADDLW R5, (R6), RSP // ERROR "illegal destination register"
LDADDLH R5, (R6), RSP // ERROR "illegal destination register"
LDADDLB R5, (R6), RSP // ERROR "illegal destination register"
LDANDAD R5, (R6), RSP // ERROR "illegal destination register"
LDANDAW R5, (R6), RSP // ERROR "illegal destination register"
LDANDAH R5, (R6), RSP // ERROR "illegal destination register"
LDANDAB R5, (R6), RSP // ERROR "illegal destination register"
LDANDALD R5, (R6), RSP // ERROR "illegal destination register"
LDANDALW R5, (R6), RSP // ERROR "illegal destination register"
LDANDALH R5, (R6), RSP // ERROR "illegal destination register"
LDANDALB R5, (R6), RSP // ERROR "illegal destination register"
LDANDD R5, (R6), RSP // ERROR "illegal destination register"
LDANDW R5, (R6), RSP // ERROR "illegal destination register"
LDANDH R5, (R6), RSP // ERROR "illegal destination register"
LDANDB R5, (R6), RSP // ERROR "illegal destination register"
LDANDLD R5, (R6), RSP // ERROR "illegal destination register"
LDANDLW R5, (R6), RSP // ERROR "illegal destination register"
LDANDLH R5, (R6), RSP // ERROR "illegal destination register"
LDANDLB R5, (R6), RSP // ERROR "illegal destination register"
LDEORAD R5, (R6), RSP // ERROR "illegal destination register"
LDEORAW R5, (R6), RSP // ERROR "illegal destination register"
LDEORAH R5, (R6), RSP // ERROR "illegal destination register"
LDEORAB R5, (R6), RSP // ERROR "illegal destination register"
LDEORALD R5, (R6), RSP // ERROR "illegal destination register"
LDEORALW R5, (R6), RSP // ERROR "illegal destination register"
LDEORALH R5, (R6), RSP // ERROR "illegal destination register"
LDEORALB R5, (R6), RSP // ERROR "illegal destination register"
LDEORD R5, (R6), RSP // ERROR "illegal destination register"
LDEORW R5, (R6), RSP // ERROR "illegal destination register"
LDEORH R5, (R6), RSP // ERROR "illegal destination register"
LDEORB R5, (R6), RSP // ERROR "illegal destination register"
LDEORLD R5, (R6), RSP // ERROR "illegal destination register"
LDEORLW R5, (R6), RSP // ERROR "illegal destination register"
LDEORLH R5, (R6), RSP // ERROR "illegal destination register"
LDEORLB R5, (R6), RSP // ERROR "illegal destination register"
LDORAD R5, (R6), RSP // ERROR "illegal destination register"
LDORAW R5, (R6), RSP // ERROR "illegal destination register"
LDORAH R5, (R6), RSP // ERROR "illegal destination register"
LDORAB R5, (R6), RSP // ERROR "illegal destination register"
LDORALD R5, (R6), RSP // ERROR "illegal destination register"
LDORALW R5, (R6), RSP // ERROR "illegal destination register"
LDORALH R5, (R6), RSP // ERROR "illegal destination register"
LDORALB R5, (R6), RSP // ERROR "illegal destination register"
LDORD R5, (R6), RSP // ERROR "illegal destination register"
LDORW R5, (R6), RSP // ERROR "illegal destination register"
LDORH R5, (R6), RSP // ERROR "illegal destination register"
LDORB R5, (R6), RSP // ERROR "illegal destination register"
LDORLD R5, (R6), RSP // ERROR "illegal destination register"
LDORLW R5, (R6), RSP // ERROR "illegal destination register"
LDORLH R5, (R6), RSP // ERROR "illegal destination register"
LDORLB R5, (R6), RSP // ERROR "illegal destination register"
SWPAD R5, (R6), RSP // ERROR "illegal destination register"
SWPAW R5, (R6), RSP // ERROR "illegal destination register"
SWPAH R5, (R6), RSP // ERROR "illegal destination register"
SWPAB R5, (R6), RSP // ERROR "illegal destination register"
SWPALD R5, (R6), RSP // ERROR "illegal destination register"
SWPALW R5, (R6), RSP // ERROR "illegal destination register"
SWPALH R5, (R6), RSP // ERROR "illegal destination register"
SWPALB R5, (R6), RSP // ERROR "illegal destination register"
SWPD R5, (R6), RSP // ERROR "illegal destination register"
SWPW R5, (R6), RSP // ERROR "illegal destination register"
SWPH R5, (R6), RSP // ERROR "illegal destination register"
SWPB R5, (R6), RSP // ERROR "illegal destination register"
SWPLD R5, (R6), RSP // ERROR "illegal destination register"
SWPLW R5, (R6), RSP // ERROR "illegal destination register"
SWPLH R5, (R6), RSP // ERROR "illegal destination register"
SWPLB R5, (R6), RSP // ERROR "illegal destination register"
STXR R5, (R6), RSP // ERROR "illegal destination register"
STXRW R5, (R6), RSP // ERROR "illegal destination register"
STLXR R5, (R6), RSP // ERROR "illegal destination register"
STLXRW R5, (R6), RSP // ERROR "illegal destination register"
STXP (R5, R7), (R6), RSP // ERROR "illegal destination register"
STXPW (R5, R7), (R6), RSP // ERROR "illegal destination register"
STLXP (R5, R7), (R6), RSP // ERROR "illegal destination register"
STLXP (R5, R7), (R6), RSP // ERROR "illegal destination register"
RET RET

View file

@ -424,7 +424,15 @@ label4:
CALL foo(SB) CALL foo(SB)
RET foo(SB) RET foo(SB)
// unary operation
NEGW R1, R2 // 00011023 NEGW R1, R2 // 00011023
CLZ R1, R2 // 70221020
CLO R1, R2 // 70221021
// to (Hi, Lo)
MADD R2, R1 // 70220000
MSUB R2, R1 // 70220004
MUL R2, R1 // 00220018
// END // END
// //

View file

@ -1021,18 +1021,24 @@ label1:
// VSX move from VSR, XX1-form // VSX move from VSR, XX1-form
// <MNEMONIC> XS,RA produces // <MNEMONIC> XS,RA produces
// <mnemonic> RA,XS // <mnemonic> RA,XS
// Extended mnemonics accept VMX and FP registers as sources
MFVSRD VS0, R1 MFVSRD VS0, R1
MFVSRWZ VS33, R1 MFVSRWZ VS33, R1
MFVSRLD VS63, R1 MFVSRLD VS63, R1
MFVRD V0, R1
MFFPRD F0, R1
// VSX move to VSR, XX1-form // VSX move to VSR, XX1-form
// <MNEMONIC> RA,XT produces // <MNEMONIC> RA,XT produces
// <mnemonic> XT,RA // <mnemonic> XT,RA
// Extended mnemonics accept VMX and FP registers as targets
MTVSRD R1, VS0 MTVSRD R1, VS0
MTVSRWA R1, VS31 MTVSRWA R1, VS31
MTVSRWZ R1, VS63 MTVSRWZ R1, VS63
MTVSRDD R1, R2, VS0 MTVSRDD R1, R2, VS0
MTVSRWS R1, VS32 MTVSRWS R1, VS32
MTVRD R1, V13
MTFPRD R1, F24
// VSX AND, XX3-form // VSX AND, XX3-form
// <MNEMONIC> XA,XB,XT produces // <MNEMONIC> XA,XB,XT produces

View file

@ -66,6 +66,7 @@ TEXT main·foo(SB),DUPOK|NOSPLIT,$16-0 // TEXT main.foo(SB), DUPOK|NOSPLIT, $16-
ADD $32768, R1, R2 // b9040021c22800008000 ADD $32768, R1, R2 // b9040021c22800008000
ADDC R1, R2 // b9ea1022 ADDC R1, R2 // b9ea1022
ADDC $1, R1, R2 // ec21000100db ADDC $1, R1, R2 // ec21000100db
ADDC $-1, R1, R2 // ec21ffff00db
ADDC R1, R2, R3 // b9ea1032 ADDC R1, R2, R3 // b9ea1032
ADDW R1, R2 // 1a21 ADDW R1, R2 // 1a21
ADDW R1, R2, R3 // b9f81032 ADDW R1, R2, R3 // b9f81032
@ -182,6 +183,21 @@ TEXT main·foo(SB),DUPOK|NOSPLIT,$16-0 // TEXT main.foo(SB), DUPOK|NOSPLIT, $16-
XORW (R1), R2 // 57201000 XORW (R1), R2 // 57201000
XORW -1(R1), R2 // e3201fffff57 XORW -1(R1), R2 // e3201fffff57
RNSBG $0, $31, $32, R1, R2 // ec21001f2054
RXSBG $17, $8, $16, R3, R4 // ec4311081057
ROSBG $9, $24, $11, R5, R6 // ec6509180b56
RNSBGT $0, $31, $32, R7, R8 // ec87801f2054
RXSBGT $17, $8, $16, R9, R10 // eca991081057
ROSBGT $9, $24, $11, R11, R0 // ec0b89180b56
RISBG $0, $31, $32, R1, R2 // ec21001f2055
RISBGN $17, $8, $16, R3, R4 // ec4311081059
RISBGZ $9, $24, $11, R5, R6 // ec6509980b55
RISBGNZ $0, $31, $32, R7, R8 // ec87009f2059
RISBHG $17, $8, $16, R9, R10 // eca91108105d
RISBLG $9, $24, $11, R11, R0 // ec0b09180b51
RISBHGZ $17, $8, $16, R9, R10 // eca91188105d
RISBLGZ $9, $24, $11, R11, R0 // ec0b09980b51
LAA R1, R2, 524287(R3) // eb213fff7ff8 LAA R1, R2, 524287(R3) // eb213fff7ff8
LAAG R4, R5, -524288(R6) // eb54600080e8 LAAG R4, R5, -524288(R6) // eb54600080e8
LAAL R7, R8, 8192(R9) // eb87900002fa LAAL R7, R8, 8192(R9) // eb87900002fa
@ -219,6 +235,9 @@ TEXT main·foo(SB),DUPOK|NOSPLIT,$16-0 // TEXT main.foo(SB), DUPOK|NOSPLIT, $16-
TMLH R3, $0 // a7300000 TMLH R3, $0 // a7300000
TMLL R4, $32768 // a7418000 TMLL R4, $32768 // a7418000
IPM R3 // b2220030
IPM R12 // b22200c0
BNE 0(PC) // a7740000 BNE 0(PC) // a7740000
BEQ 0(PC) // a7840000 BEQ 0(PC) // a7840000
BLT 0(PC) // a7440000 BLT 0(PC) // a7440000

View file

@ -83,7 +83,7 @@ func main() {
} }
} }
if ok && !*flags.SymABIs { if ok && !*flags.SymABIs {
obj.WriteObjFile(ctxt, buf) obj.WriteObjFile(ctxt, buf, "")
} }
if !ok || diag { if !ok || diag {
if failedFile != "" { if failedFile != "" {

View file

@ -200,18 +200,6 @@ func (f *File) saveExprs(x interface{}, context astContext) {
} }
case *ast.CallExpr: case *ast.CallExpr:
f.saveCall(x, context) f.saveCall(x, context)
case *ast.GenDecl:
if x.Tok == token.CONST {
for _, spec := range x.Specs {
vs := spec.(*ast.ValueSpec)
if vs.Type == nil {
for _, name := range spec.(*ast.ValueSpec).Names {
consts[name.Name] = true
}
}
}
}
} }
} }

View file

@ -148,6 +148,8 @@ C.long, C.ulong (unsigned long), C.longlong (long long),
C.ulonglong (unsigned long long), C.float, C.double, C.ulonglong (unsigned long long), C.float, C.double,
C.complexfloat (complex float), and C.complexdouble (complex double). C.complexfloat (complex float), and C.complexdouble (complex double).
The C type void* is represented by Go's unsafe.Pointer. The C type void* is represented by Go's unsafe.Pointer.
The C sized integer types (int8_t, uint8_t, ) are represented by their Go
counterparts (int8, uint8, ).
The C types __int128_t and __uint128_t are represented by [16]byte. The C types __int128_t and __uint128_t are represented by [16]byte.
A few special C types which would normally be represented by a pointer A few special C types which would normally be represented by a pointer
@ -296,7 +298,7 @@ Go functions can be exported for use by C code in the following way:
They will be available in the C code as: They will be available in the C code as:
extern int64 MyFunction(int arg1, int arg2, GoString arg3); extern int64_t MyFunction(int arg1, int arg2, GoString arg3);
extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3); extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);
found in the _cgo_export.h generated header, after any preambles found in the _cgo_export.h generated header, after any preambles
@ -710,7 +712,7 @@ _cgo_main.c:
int main() { return 0; } int main() { return 0; }
void crosscall2(void(*fn)(void*, int, uintptr_t), void *a, int c, uintptr_t ctxt) { } void crosscall2(void(*fn)(void*, int, uintptr_t), void *a, int c, uintptr_t ctxt) { }
uintptr_t _cgo_wait_runtime_init_done() { return 0; } uintptr_t _cgo_wait_runtime_init_done(void) { return 0; }
void _cgo_release_context(uintptr_t ctxt) { } void _cgo_release_context(uintptr_t ctxt) { }
char* _cgo_topofstack(void) { return (char*)0; } char* _cgo_topofstack(void) { return (char*)0; }
void _cgo_allocate(void *a, int c) { } void _cgo_allocate(void *a, int c) { }

View file

@ -23,6 +23,7 @@ import (
"internal/xcoff" "internal/xcoff"
"math" "math"
"os" "os"
"regexp"
"strconv" "strconv"
"strings" "strings"
"unicode" "unicode"
@ -897,21 +898,16 @@ func (p *Package) rewriteCall(f *File, call *Call) (string, bool) {
needsUnsafe = true needsUnsafe = true
} }
// Explicitly convert untyped constants to the // Use "var x T = ..." syntax to explicitly convert untyped
// parameter type, to avoid a type mismatch. // constants to the parameter type, to avoid a type mismatch.
if p.isConst(f, arg) { ptype := p.rewriteUnsafe(param.Go)
ptype := p.rewriteUnsafe(param.Go)
if !p.needsPointerCheck(f, param.Go, args[i]) || param.BadPointer {
if ptype != param.Go { if ptype != param.Go {
needsUnsafe = true needsUnsafe = true
} }
arg = &ast.CallExpr{ fmt.Fprintf(&sb, "var _cgo%d %s = %s; ", i,
Fun: ptype, gofmtLine(ptype), gofmtPos(arg, origArg.Pos()))
Args: []ast.Expr{arg},
}
}
if !p.needsPointerCheck(f, param.Go, args[i]) {
fmt.Fprintf(&sb, "_cgo%d := %s; ", i, gofmtPos(arg, origArg.Pos()))
continue continue
} }
@ -1254,47 +1250,6 @@ func (p *Package) isType(t ast.Expr) bool {
return false return false
} }
// isConst reports whether x is an untyped constant expression.
func (p *Package) isConst(f *File, x ast.Expr) bool {
switch x := x.(type) {
case *ast.BasicLit:
return true
case *ast.SelectorExpr:
id, ok := x.X.(*ast.Ident)
if !ok || id.Name != "C" {
return false
}
name := f.Name[x.Sel.Name]
if name != nil {
return name.IsConst()
}
case *ast.Ident:
return x.Name == "nil" ||
strings.HasPrefix(x.Name, "_Ciconst_") ||
strings.HasPrefix(x.Name, "_Cfconst_") ||
strings.HasPrefix(x.Name, "_Csconst_") ||
consts[x.Name]
case *ast.UnaryExpr:
return p.isConst(f, x.X)
case *ast.BinaryExpr:
return p.isConst(f, x.X) && p.isConst(f, x.Y)
case *ast.ParenExpr:
return p.isConst(f, x.X)
case *ast.CallExpr:
// Calling the builtin function complex on two untyped
// constants returns an untyped constant.
// TODO: It's possible to construct a case that will
// erroneously succeed if there is a local function
// named "complex", shadowing the builtin, that returns
// a numeric type. I can't think of any cases that will
// erroneously fail.
if id, ok := x.Fun.(*ast.Ident); ok && id.Name == "complex" && len(x.Args) == 2 {
return p.isConst(f, x.Args[0]) && p.isConst(f, x.Args[1])
}
}
return false
}
// isVariable reports whether x is a variable, possibly with field references. // isVariable reports whether x is a variable, possibly with field references.
func (p *Package) isVariable(x ast.Expr) bool { func (p *Package) isVariable(x ast.Expr) bool {
switch x := x.(type) { switch x := x.(type) {
@ -1633,6 +1588,7 @@ func (p *Package) gccCmd() []string {
c = append(c, p.gccMachine()...) c = append(c, p.gccMachine()...)
if goos == "aix" { if goos == "aix" {
c = append(c, "-maix64") c = append(c, "-maix64")
c = append(c, "-mcmodel=large")
} }
c = append(c, "-") //read input from standard input c = append(c, "-") //read input from standard input
return c return c
@ -2091,6 +2047,8 @@ type typeConv struct {
ptrSize int64 ptrSize int64
intSize int64 intSize int64
exactWidthIntegerTypes map[string]*Type
} }
var tagGen int var tagGen int
@ -2133,6 +2091,21 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
} else { } else {
c.goVoidPtr = c.Ident("unsafe.Pointer") c.goVoidPtr = c.Ident("unsafe.Pointer")
} }
c.exactWidthIntegerTypes = make(map[string]*Type)
for _, t := range []ast.Expr{
c.int8, c.int16, c.int32, c.int64,
c.uint8, c.uint16, c.uint32, c.uint64,
} {
name := t.(*ast.Ident).Name
u := new(Type)
*u = *goTypes[name]
if u.Align > ptrSize {
u.Align = ptrSize
}
u.Go = t
c.exactWidthIntegerTypes[name] = u
}
} }
// base strips away qualifiers and typedefs to get the underlying type // base strips away qualifiers and typedefs to get the underlying type
@ -2504,6 +2477,26 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
t.Align = c.ptrSize t.Align = c.ptrSize
break break
} }
// Exact-width integer types. These are always compatible with
// the corresponding Go types since the C standard requires
// them to have no padding bit and use the twos complement
// representation.
if exactWidthIntegerType.MatchString(dt.Name) {
sub := c.Type(dt.Type, pos)
goname := strings.TrimPrefix(dt.Name, "__")
goname = strings.TrimSuffix(goname, "_t")
u := c.exactWidthIntegerTypes[goname]
if sub.Size != u.Size {
fatalf("%s: unexpected size: %d vs. %d %s", lineno(pos), sub.Size, u.Size, dtype)
}
if sub.Align != u.Align {
fatalf("%s: unexpected alignment: %d vs. %d %s", lineno(pos), sub.Align, u.Align, dtype)
}
t.Size = u.Size
t.Align = u.Align
t.Go = u.Go
break
}
name := c.Ident("_Ctype_" + dt.Name) name := c.Ident("_Ctype_" + dt.Name)
goIdent[name.Name] = name goIdent[name.Name] = name
sub := c.Type(dt.Type, pos) sub := c.Type(dt.Type, pos)
@ -2511,13 +2504,16 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
// Treat this typedef as a uintptr. // Treat this typedef as a uintptr.
s := *sub s := *sub
s.Go = c.uintptr s.Go = c.uintptr
s.BadPointer = true
sub = &s sub = &s
// Make sure we update any previously computed type. // Make sure we update any previously computed type.
if oldType := typedef[name.Name]; oldType != nil { if oldType := typedef[name.Name]; oldType != nil {
oldType.Go = sub.Go oldType.Go = sub.Go
oldType.BadPointer = true
} }
} }
t.Go = name t.Go = name
t.BadPointer = sub.BadPointer
if unionWithPointer[sub.Go] { if unionWithPointer[sub.Go] {
unionWithPointer[t.Go] = true unionWithPointer[t.Go] = true
} }
@ -2527,6 +2523,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
if oldType == nil { if oldType == nil {
tt := *t tt := *t
tt.Go = sub.Go tt.Go = sub.Go
tt.BadPointer = sub.BadPointer
typedef[name.Name] = &tt typedef[name.Name] = &tt
} }
@ -2635,6 +2632,8 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
return t return t
} }
var exactWidthIntegerType = regexp.MustCompile(`^(__)?u?int(8|16|32|64)_t$`)
// isStructUnionClass reports whether the type described by the Go syntax x // isStructUnionClass reports whether the type described by the Go syntax x
// is a struct, union, or class with a tag. // is a struct, union, or class with a tag.
func isStructUnionClass(x ast.Expr) bool { func isStructUnionClass(x ast.Expr) bool {

View file

@ -136,21 +136,31 @@ func gofmt(n interface{}) string {
// (due to the printer possibly inserting newlines because of position // (due to the printer possibly inserting newlines because of position
// information) operators. // information) operators.
var gofmtLineReplacer = strings.NewReplacer( var gofmtLineReplacer = strings.NewReplacer(
"{\n", "{", // Want to replace \n without ; after everything from
",\n", ",", // https://golang.org/ref/spec#Operators_and_punctuation
// EXCEPT ++ -- ) ] }
"++\n", "++;", "++\n", "++;",
"--\n", "--;", "--\n", "--;",
"+\n", "+",
"-\n", "-", "+\n", "+ ",
"*\n", "*", "-\n", "- ",
"/\n", "/", "*\n", "* ",
"%\n", "%", "/\n", "/ ",
"&\n", "&", "%\n", "% ",
"|\n", "|", "&\n", "& ",
"^\n", "^", "|\n", "| ",
"<\n", "<", "^\n", "^ ",
">\n", ">", "<\n", "< ",
"=\n", "=", ">\n", "> ",
"=\n", "= ",
"!\n", "! ", // not possible in gofmt today
"(\n", "(",
"[\n", "[", // not possible in gofmt today
"{\n", "{",
",\n", ",",
".\n", ". ",
":\n", ": ", // not possible in gofmt today
"\n", ";", "\n", ";",
) )

Some files were not shown because too many files have changed in this diff Show more