Compare commits

..

31 Commits

Author SHA1 Message Date
Russ Cox
357c914136 [release-branch.go1.8] go1.8.7
Change-Id: Ida9b4f44033f33657dad213f65b0c85ad89b08a7
Reviewed-on: https://team-review.git.corp.google.com/213169
Reviewed-by: Andrew Bonventre <andybons@google.com>
2018-02-07 15:33:09 +00:00
Russ Cox
9574ce9cf6 [release-branch.go1.8] doc: document Go 1.8.7
Change-Id: I7ea97312bdf489c2833b1823dd633eb55f3bcd72
Reviewed-on: https://team-review.git.corp.google.com/213168
Reviewed-by: Andrew Bonventre <andybons@google.com>
2018-02-07 15:33:05 +00:00
Russ Cox
44821583bc [release-branch.go1.8] cmd/go: accept only limited compiler and linker flags in #cgo directives
Both gcc and clang accept an option -fplugin=code.so to load
a plugin from the ELF shared object file code.so.
Obviously that plugin can then do anything it wants
during the build. This is contrary to the goal of "go get"
never running untrusted code during the build.
(What happens if you choose to run the result of
the build is your responsibility.)

Disallow this behavior by only allowing a small set of
known command-line flags in #cgo CFLAGS directives
(and #cgo LDFLAGS, etc).

The new restrictions can be adjusted by the environment
variables CGO_CFLAGS_ALLOW, CGO_CFLAGS_DISALLOW,
and so on. See the documentation.

In addition to excluding cgo-defined flags, we also have to
make sure that when we pass file names on the command
line, they don't look like flags. So we now refuse to build
packages containing suspicious file names like -x.go.

A wrinkle in all this is that GNU binutils uniformly accept
@foo on the command line to mean "if the file foo exists,
then substitute its contents for @foo in the command line".
So we must also reject @x.go, flags and flag arguments
beginning with @, and so on.

Fixes #23674, CVE-2018-6574.

Change-Id: I59e7c1355155c335a5c5ae0d2cf8fa7aa313940a
Reviewed-on: https://team-review.git.corp.google.com/212688
Reviewed-by: Ian Lance Taylor <iant@google.com>
2018-02-07 14:16:33 +00:00
Andrew Bonventre
96c72e9468 [release-branch.go1.8] go1.8.6
Change-Id: I0aeac01cb7a4329129351d3175f11a0a50b7466c
Reviewed-on: https://go-review.googlesource.com/89195
Run-TryBot: Andrew Bonventre <andybons@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Bonventre <andybons@golang.org>
2018-01-23 03:33:54 +00:00
Andrew Bonventre
89e6a4d6d0 [release-branch.go1.8] doc: document Go 1.8.6
Update golang/go#23515

Change-Id: Id334d8663bf4cbb68f224d1bba4c9ad3855f8aae
Reviewed-on: https://go-review.googlesource.com/89155
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-on: https://go-review.googlesource.com/89157
Run-TryBot: Andrew Bonventre <andybons@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Bonventre <andybons@golang.org>
2018-01-23 03:27:44 +00:00
Alberto Donizetti
a5a3be1636 [release-branch.go1.8] math/big: protect against aliasing in nat.divLarge
In nat.divLarge (having signature (z nat).divLarge(u, uIn, v nat)),
we check whether z aliases uIn or v, but aliasing is currently not
checked for the u parameter.

Unfortunately, z and u aliasing each other can in some cases cause
errors in the computation.

The q return parameter (which will hold the result's quotient), is
unconditionally initialized as

    q = z.make(m + 1)

When cap(z) ≥ m+1, z.make() will reuse z's backing array, causing q
and z to share the same backing array. If then z aliases u, setting q
during the quotient computation will then corrupt u, which at that
point already holds computation state.

To fix this, we add an alias(z, u) check at the beginning of the
function, taking care of aliasing the same way we already do for uIn
and v.

Fixes #22830

Change-Id: I3ab81120d5af6db7772a062bb1dfc011de91f7ad
Reviewed-on: https://go-review.googlesource.com/78995
Run-TryBot: Alberto Donizetti <alb.donizetti@gmail.com>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Reviewed-on: https://go-review.googlesource.com/89156
Run-TryBot: Andrew Bonventre <andybons@golang.org>
Reviewed-by: Andrew Bonventre <andybons@golang.org>
2018-01-23 03:27:42 +00:00
Andrew Bonventre
45a42c9be5 [release-branch.go1.8] doc: hide blog content for golang.google.cn
/blog redirects to blog.golang.org (currently blocked in China)
unless there is a local checkout of golang.org/x/blog, which is
not possible on App Engine Classic.

Change-Id: Ia695e663c9bebcc6c3bedea324c630299eaad4dc
Reviewed-on: https://go-review.googlesource.com/53051
Reviewed-by: Chris Broadfoot <cbro@golang.org>
Reviewed-on: https://go-review.googlesource.com/81175
Reviewed-by: Russ Cox <rsc@golang.org>
2017-11-30 21:11:42 +00:00
Andrew Bonventre
6c733cd93b [release-branch.go1.8] doc: hide video and share if being served from CN
In the case where requests are coming from mainland China, hide
links to locations that are blocked and functionality that is
not permitted.

Additionally, some very small cleanup of the JS.

This change requires https://go-review.googlesource.com/c/52873

Change-Id: I7fc68748e629dbe5b966d6bf117e7f7b546966eb
Reviewed-on: https://go-review.googlesource.com/52872
Reviewed-by: Chris Broadfoot <cbro@golang.org>
Reviewed-on: https://go-review.googlesource.com/81095
Reviewed-by: Russ Cox <rsc@golang.org>
2017-11-30 19:41:18 +00:00
Russ Cox
d4ccbd8833 [release-branch.go1.8] go1.8.5
Change-Id: I7c6cf169e84329a31d2d9dc4c52d5c29e80482c9
Reviewed-on: https://go-review.googlesource.com/71350
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Chris Broadfoot <cbro@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-10-25 18:57:21 +00:00
Russ Cox
79be6cb389 [release-branch.go1.8] doc: document Go 1.8.5
Change-Id: I9241e6acb65c337b961eed9cdeaf4c041b6326a3
Reviewed-on: https://go-review.googlesource.com/73390
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Chris Broadfoot <cbro@golang.org>
Reviewed-on: https://go-review.googlesource.com/73392
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-10-25 18:57:19 +00:00
Michael Hudson-Doyle
b838f943ab [release-branch.go1.8] cmd/internal/obj/x86: use LEAx rather than ADDx when calling DUFFxxxx via GOT
DUFFZERO on 386 is not marked as clobbering flags, but rewriteToUseGot rewrote
"ADUFFZERO $offset" to "MOVL runtime.duffxxx@GOT, CX; ADDL $offset, CX; CALL CX"
which does. Luckily the fix is easier than figuring out what the problem was:
replace the ADDL $offset, CX with LEAL $offset(CX), CX.

On amd64 DUFFZERO clobbers flags, on arm, arm64 and ppc64 ADD does not clobber
flags and s390x does not use the duff functions, so I'm fairly confident this
is the only fix required.

I don't know how to write a test though.

Change-Id: I69b0958f5f45771d61db5f5ecb4ded94e8960d4d
Reviewed-on: https://go-review.googlesource.com/41821
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-on: https://go-review.googlesource.com/70871
Run-TryBot: Russ Cox <rsc@golang.org>
2017-10-25 18:57:16 +00:00
Adam Langley
3be9637d56 [release-branch.go1.8] crypto/x509: reject intermediates with unknown critical extensions.
In https://golang.org/cl/9390 I messed up and put the critical extension
test in the wrong function. Thus it only triggered for leaf certificates
and not for intermediates or roots.

In practice, this is not expected to have a security impact in the web
PKI.

[Merge conflicts resolved in verify_test.go]

Change-Id: I4f2464ef2fb71b5865389901f293062ba1327702
Reviewed-on: https://go-review.googlesource.com/69294
Run-TryBot: Adam Langley <agl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-on: https://go-review.googlesource.com/70842
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2017-10-25 18:57:14 +00:00
Lynn Boger
2eac89d5c8 [release-branch.go1.8] cmd/link: implement trampolines for ppc64le with ext linking
When using golang on ppc64le there have been issues
when building executables that generate extremely large text
sections.  This is due to the call instruction and the limitation
on the offset field, which is smaller than most platforms.  If the
size of the call target offset is too big for the offset field in
the call instruction, then link errors can occur.

The original solution to this problem in golang was to split the
text section when it became too large, allowing the external (GNU)
linker to insert the necessary stub to handle the long call.  That
worked fine until the another size limit for the program size was hit,
where a plt_branch was created instead of a long branch.  In that case
the plt_branch code sequence expects r2 to contain the address of the
TOC, but when golang creates dynamic executables by default
(-buildmode=exe) r2 does not always contain the address of the TOC
and as a result when building programs that reach this extremely
large size, a runtime SEGV or SIGILL can occur due to branching to a bad
address.

When using internal linking, trampolines are generated to handle the
long calls but the text sections are not split.  With this change,
text sections will still be split approrpriately with external linking
but if the buildmode being used does not maintain r2 as the TOC
addresses, then trampolines will be created for those calls.

Fixes #20497

Change-Id: If5400b0f86c2c08e106b332be6db0b259b07d93d
Reviewed-on: https://go-review.googlesource.com/45130
Run-TryBot: Lynn Boger <laboger@linux.vnet.ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-on: https://go-review.googlesource.com/70837
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com>
2017-10-25 18:57:11 +00:00
Russ Cox
142d449081 [release-branch.go1.8] cmd/go: clean up x.exe properly in TestImportMain
More generally I'm concerned about these tests using
$GOROOT/src/cmd/go as scratch space, especially
combined wtih tg.parallel() - it's easy to believe some other
test might inadvertently also try to write x.exe about the
same time. This CL only solves the "didn't clean up x.exe"
problem and leaves for another day the "probably shouldn't
write to cmd/go at all" problem.

Fixes #22266.

Change-Id: I651534d70e2d360138e0373fb4a316081872550b
Reviewed-on: https://go-review.googlesource.com/71410
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/71490
2017-10-25 18:57:08 +00:00
Ian Lance Taylor
533ee44cd4 [release-branch.go1.8] cmd/go: correct directory used in checkNestedVCS test
This error was not used when using git because nested git is permitted.
Add test using Mercurial, so that at least we have a test, even though
the test is not run by default.

Fixes #22157
Fixes #22201

Change-Id: If521f3c09b0754e00e56fa3cd0364764a57a43ad
Reviewed-on: https://go-review.googlesource.com/69670
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-on: https://go-review.googlesource.com/70839
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-10-25 18:57:06 +00:00
Jeff
8093678ae1 [release-branch.go1.8] net/smtp: NewClient: set tls field to true when already using a TLS connection
Change-Id: I34008f56c191df0edcaafc20d569bbc6184f89fc
Reviewed-on: https://go-review.googlesource.com/68470
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/70843
Run-TryBot: Russ Cox <rsc@golang.org>
2017-10-25 18:57:03 +00:00
Author Name
0bf8909ff8 [release-branch.go1.8] net: increase expected time to dial a closed port on all Darwin ports
All current darwin architectures seem to take at least 100ms to dial a closed port,
and that was making the all.bash script fail.

Fixes #22062

Change-Id: Ib79c4b7a5db2373c95ce5d993cdcbee55cc0667f
Reviewed-on: https://go-review.googlesource.com/67350
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/71331
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-10-25 18:57:00 +00:00
Elias Naur
b3b1e12b13 [release-branch.go1.8] net: bump TestDialerDualStackFDLeak timeout on iOS
On an iPhone 6 running iOS 11, the TestDialerDualStackFDLeak test
started failing with dial durations just above the limit:

FAIL: TestDialerDualStackFDLeak (0.21s)

	dial_test.go:90: got 101.154ms; want <= 95ms

Bump the timeout on iOS.

For the iOS builder.

Change-Id: Id42b471e7cf7d0c84f6e83ed04b395fa1a2d449d
Reviewed-on: https://go-review.googlesource.com/66491
Run-TryBot: Elias Naur <elias.naur@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/71330
Run-TryBot: Russ Cox <rsc@golang.org>
2017-10-25 18:56:57 +00:00
pvoicu
1ab2a4e85f [release-branch.go1.8] runtime: fix usleep by correctly setting nanoseconds parameter for pselect6
Fixes #21518

Change-Id: Idd67e3f0410d0ce991b34dcc0c8f15e0d5c529c9
Reviewed-on: https://go-review.googlesource.com/56850
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-on: https://go-review.googlesource.com/70838
Run-TryBot: Russ Cox <rsc@golang.org>
2017-10-25 18:56:55 +00:00
Brad Fitzpatrick
25be91ae4f [release-branch.go1.8] doc: delete go1.8.txt
Fixes #20591

Change-Id: I2a4674a3430c5a4d3c569f3ea654c6ff4d9bf7ee
Reviewed-on: https://go-review.googlesource.com/45015
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/70836
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-10-25 18:56:52 +00:00
Cherry Zhang
82cfda2910 [release-branch.go1.8] cmd/compile: fix subword store/load elision for MIPS
Apply the fix in CL 44355 to MIPS.

ARM64 has these rules but commented out for performance reason.
Fix the commented rules, in case they are enabled in the future.

Enhance the test so it triggers the failure on ARM and MIPS without
the fix.

Updates #20530.

Change-Id: I82d77448e3939a545fe519d0a29a164f8fa5417c
Reviewed-on: https://go-review.googlesource.com/44430
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-on: https://go-review.googlesource.com/70840
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2017-10-25 18:56:49 +00:00
David Chase
9ccc2921dd [release-branch.go1.8] cmd/compile: fix subword store/load elision for amd64, x86, arm
Replacing byteload-of-bytestore-of-x with x is incorrect
when x contains a larger-than-byte value (and so on for
16 and 32-bit load/store pairs).  Replace "x" with the
appropriate zero/sign extension of x, which if unnecessary
will be repaired by other rules.

Made logic for arm match x86 and amd64; yields minor extra
optimization, plus I am (much) more confident it's correct,
despite inability to reproduce bug on arm.

Ppc64 lacks this optimization, hence lacks this problem.

See related https://golang.org/cl/37154/
Fixes #20530.

[Merge conflicts in generated rewrite files resolved by
regenerating from scratch, using the programs in ssa/gen.]

Change-Id: I6af9cac2ad43bee99cafdcb04725ce7e55a43323
Reviewed-on: https://go-review.googlesource.com/44355
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-on: https://go-review.googlesource.com/70841
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2017-10-25 18:56:46 +00:00
Kenny Grant
ead964dc80 [release-branch.go1.8] net/http: Fix TestLinuxSendfile without strace permissions
If go doesn't have permission to run strace, this test hangs while
waiting for strace to run. Instead try invoking strace with
Run() first - on fail skip and report error, otherwise run
the test normally using strace.

Also fix link to open mips64 issue in same test.

Fixes #9711

Change-Id: Ibbc5fbb143ea6d0f8b6cfdca4b385ef4c8960b3d
Reviewed-on: https://go-review.googlesource.com/38633
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-on: https://go-review.googlesource.com/72170
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-10-25 18:56:43 +00:00
Michael Munday
7e9658fea9 [release-branch.go1.8] cmd/compile: zero extend when replacing load-hit-store on s390x
Keith pointed out that these rules should zero extend during the review
of CL 36845. In practice the generic rules are responsible for eliminating
most load-hit-stores and they do not have this problem. When the s390x
rules are triggered any cast following the elided load-hit-store is
kept because of the sequence the rules are applied in (i.e. the load is
removed before the zero extension gets a chance to be merged into the load).
It is therefore not clear that this issue results in any functional bugs.

This CL includes a test, but it only tests the generic rules currently.

Change-Id: Idbc43c782097a3fb159be293ec3138c5b36858ad
Reviewed-on: https://go-review.googlesource.com/37154
Run-TryBot: Michael Munday <munday@ca.ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-on: https://go-review.googlesource.com/70831
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Michael Munday <mike.munday@ibm.com>
2017-10-25 18:56:40 +00:00
Brad Fitzpatrick
7e2cd1d81e [release-branch.go1.8] net: skip Windows test using getmac if getmac cmdlet not available
This doesn't appear to be present on Windows Server 2012 or 2016:

https://build.golang.org/log/6ea21b99c9b8a2be20f9aeaec6c425b84faf1af7
https://build.golang.org/log/2bcf04f1df003577352f4f987a39a59a081094ee

Updates golang/go#17513
Updates golang/go#20073

Change-Id: I72820704b4cb16bb1720b7f6a9f2e10028c71334
Reviewed-on: https://go-review.googlesource.com/41395
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Reviewed-on: https://go-review.googlesource.com/70845
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-10-25 18:56:37 +00:00
Chris Broadfoot
f5bcb9b8fe [release-branch.go1.8] go1.8.4
Change-Id: Iae6c1ccd1e42656fa5a57d6367e43085143cd590
Reviewed-on: https://go-review.googlesource.com/68234
Reviewed-by: Russ Cox <rsc@golang.org>
2017-10-04 18:39:32 +00:00
Russ Cox
4be3fc33ef [release-branch.go1.8] net/smtp: fix PlainAuth to refuse to send passwords to non-TLS servers
PlainAuth originally refused to send passwords to non-TLS servers
and was documented as such.

In 2013, issue #5184 was filed objecting to the TLS requirement,
despite the fact that it is spelled out clearly in RFC 4954.
The only possibly legitimate use case raised was using PLAIN auth
for connections to localhost, and the suggested fix was to let the
server decide: if it advertises that PLAIN auth is OK, believe it.
That approach was adopted in CL 8279043 and released in Go 1.1.

Unfortunately, this is exactly wrong. The whole point of the TLS
requirement is to make sure not to send the password to the wrong
server or to a man-in-the-middle. Instead of implementing this rule,
CL 8279043 blindly trusts the server, so that if a man-in-the-middle
says "it's OK, you can send me your password," PlainAuth does.
And the documentation was not updated to reflect any of this.

This CL restores the original TLS check, as required by RFC 4954
and as promised in the documentation for PlainAuth.
It then carves out a documented exception for connections made
to localhost (defined as "localhost", "127.0.0.1", or "::1").

Cherry-pick of CL 68170.

Change-Id: I1d3729bbd33aa2f11a03f4c000e6bb473164957b
Reviewed-on: https://go-review.googlesource.com/68023
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-10-04 18:19:06 +00:00
Russ Cox
a4544a0f8a [release-branch.go1.8] cmd/go: reject update of VCS inside VCS
Cherry-pick of CL 68110.

Change-Id: Iae84c6404ab5eeb6950faa2364f97a017c67c506
Reviewed-on: https://go-review.googlesource.com/68190
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-10-04 18:15:44 +00:00
Russ Cox
9d1d78c34c [release-branch.go1.8] runtime: deflake TestPeriodicGC
It was only waiting 0.1 seconds for the two GCs it wanted.
Let it wait 1 second.

Change-Id: Ib3cdc8127cbf95694a9f173643c02529a85063af
Reviewed-on: https://go-review.googlesource.com/68150
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Chris Broadfoot <cbro@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-10-04 18:04:50 +00:00
Alex Brainman
d45b26b1b7 [release-branch.go1.8] os: skip TestNetworkSymbolicLink if Server service is not started
Fixes #20179

Change-Id: I2b405c9a212a75aae628ad51885616d33c054191
Reviewed-on: https://go-review.googlesource.com/42190
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-on: https://go-review.googlesource.com/68030
Run-TryBot: Chris Broadfoot <cbro@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-10-04 17:03:14 +00:00
Chris Broadfoot
f3e6216450 [release-branch.go1.8] doc: update bootstrap archive URL
This includes the patch for systems that build PIE executables by
defaul

Updates #20276.

Change-Id: Iecf8dfcf11bc18d397b8075559c37e3610f825cb
Reviewed-on: https://go-review.googlesource.com/44470
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/44491
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-05-31 21:06:00 +00:00
112 changed files with 2467 additions and 1750 deletions

View File

@@ -1 +1 @@
go1.8.3.typealias
go1.8.7

View File

@@ -63,6 +63,36 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.3">Go
1.8.3 milestone</a> on our issue tracker for details.
</p>
<p>
go1.8.4 (released 2017/10/04) includes two security fixes.
It contains the same fixes as Go 1.9.1 and was released at the same time.
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.4">Go
1.8.4 milestone</a> on our issue tracker for details.
</p>
<p>
go1.8.5 (released 2017/10/25) includes fixes to the compiler, linker, runtime,
documentation, <code>go</code> command,
and the <code>crypto/x509</code> and <code>net/smtp</code> packages.
It includes a fix to a bug introduced in Go 1.8.4 that broke <code>go</code> <code>get</code>
of non-Git repositories under certain conditions.
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.5">Go
1.8.5 milestone</a> on our issue tracker for details.
</p>
<p>
go1.8.6 (released 2018/01/22) includes the the same fix in <code>math/big</code>
as Go 1.9.3 and was released at the same time.
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.6">Go
1.8.6 milestone</a> on our issue tracker for details.
</p>
<p>
go1.8.7 (released 2018/02/07) includes a security fix to “go get”.
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.7">Go
1.8.7</a> milestone on our issue tracker for details.
</p>
<h2 id="go1.7">go1.7 (released 2016/08/15)</h2>
<p>

View File

@@ -1,55 +0,0 @@
This file lists things yet to be moved into go1.8.html or deemed too
minor to mention. Either way, delete from here when done.
Tools:
go: -buildmode=c-archive now builds PIC on ELF (CL 24180)
go: mobile pkg dir change, recommend using go list in scripts (CL 24930, CL 27929)
go, dist: can set default pkg-config tool using PKG_CONFIG env var (CL 29991)
go: can set secure/insecure GIT schemes using GIT_ALLOW_PROTOCOL env var (CL 30135)
API additions and behavior changes:
cmd/compile, runtime, etc: get rid of constant FP registers (CL 28095)
cmd/compile, runtime: add go:yeswritebarrierrec pragma (CL 30938)
cmd/compile/internal/gc: enable new parser by default (CL 27203)
cmd/compile/internal/syntax: fast Go syntax trees, initial commit (CL 27195)
cmd/compile: add compiler phase timing (CL 24462)
cmd/compile: add inline explainer (CL 22782)
cmd/compile: enable flag-specified dump of specific phase+function (CL 23044)
cmd/internal/obj, cmd/link: darwin dynlink support (CL 29393)
cmd/internal/objfile: add ppc64/ppc64le disassembler support (CL 9682)
cmd/link, cmd/go: delay linking of mingwex and mingw32 until very end (CL 26670)
cmd/link: R_ADDR dynamic relocs for internal PIE (CL 29118)
cmd/link: add trampolines for too far calls in ppc64x (CL 30850)
cmd/link: allow internal PIE linking (CL 28543)
cmd/link: fix -X importpath.name=value when import path needs escaping (CL 31970)
cmd/link: fix -buildmode=pie / -linkshared combination (CL 28996)
cmd/link: for -buildmode=exe pass -no-pie to external linker (CL 33106)
cmd/link: insert trampolines for too-far jumps on ARM (CL 29397)
cmd/link: non-executable stack support for Solaris (CL 24142)
cmd/link: put text at address 0x1000000 on darwin/amd64 (CL 32185)
cmd/link: remove the -shared flag (CL 28852)
cmd/link: split large elf text sections on ppc64x (CL 27790)
cmd/link: trampoline support for external linking on ARM (CL 31143)
cmd/objdump: implement objdump of .o files (CL 24818)
go/build: allow % in ${SRCDIR} expansion for Jenkins (CL 31611)
go/build: do not record go:binary-only-package if build tags not satisfied (CL 31577)
go/build: implement default GOPATH (CL 32019)
runtime/race: update race runtime (CL 32160)
runtime: assume 64kB physical pages on ARM (CL 25021)
runtime: disable stack rescanning by default (CL 31766)
runtime: don't call cgocallback from signal handler (CL 30218)
runtime: fix check for vacuous page boundary rounding (CL 27230)
runtime: fix map iterator concurrent map check (CL 24749)
runtime: fix newextram PC passed to race detector (CL 29712)
runtime: implement unconditional hybrid barrier (CL 31765)
runtime: include pre-panic/throw logs in core dumps (CL 32013)
runtime: limit the number of map overflow buckets (CL 25049)
runtime: pass windows float syscall args via XMM (CL 32173)
runtime: print sigcode on signal crash (CL 32183)
runtime: record current PC for SIGPROF on non-Go thread (CL 30252)
runtime: sleep on CLOCK_MONOTONIC in futexsleep1 on freebsd (CL 30154)

View File

@@ -1,6 +1,6 @@
<!--{
"Title": "The Go Programming Language Specification",
"Subtitle": "Version of January 31, 2017",
"Subtitle": "Version of November 18, 2016",
"Path": "/ref/spec"
}-->
@@ -738,7 +738,7 @@ The method set of any other type <code>T</code> consists of all
The method set of the corresponding <a href="#Pointer_types">pointer type</a> <code>*T</code>
is the set of all methods declared with receiver <code>*T</code> or <code>T</code>
(that is, it also contains the method set of <code>T</code>).
Further rules apply to structs containing embedded fields, as described
Further rules apply to structs containing anonymous fields, as described
in the section on <a href="#Struct_types">struct types</a>.
Any other type has an empty method set.
In a method set, each method must have a
@@ -947,16 +947,16 @@ Moreover, the inner slices must be initialized individually.
<p>
A struct is a sequence of named elements, called fields, each of which has a
name and a type. Field names may be specified explicitly (IdentifierList) or
implicitly (EmbeddedField).
implicitly (AnonymousField).
Within a struct, non-<a href="#Blank_identifier">blank</a> field names must
be <a href="#Uniqueness_of_identifiers">unique</a>.
</p>
<pre class="ebnf">
StructType = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName .
Tag = string_lit .
StructType = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl = (IdentifierList Type | AnonymousField) [ Tag ] .
AnonymousField = [ "*" ] TypeName .
Tag = string_lit .
</pre>
<pre>
@@ -974,15 +974,16 @@ struct {
</pre>
<p>
A field declared with a type but no explicit field name is called an <i>embedded field</i>.
An embedded field must be specified as
A field declared with a type but no explicit field name is an <i>anonymous field</i>,
also called an <i>embedded</i> field or an embedding of the type in the struct.
An embedded type must be specified as
a type name <code>T</code> or as a pointer to a non-interface type name <code>*T</code>,
and <code>T</code> itself may not be
a pointer type. The unqualified type name acts as the field name.
</p>
<pre>
// A struct with four embedded fields of types T1, *T2, P.T3 and *P.T4
// A struct with four anonymous fields of type T1, *T2, P.T3 and *P.T4
struct {
T1 // field name is T1
*T2 // field name is T2
@@ -999,15 +1000,15 @@ in a struct type:
<pre>
struct {
T // conflicts with embedded field *T and *P.T
*T // conflicts with embedded field T and *P.T
*P.T // conflicts with embedded field T and *T
T // conflicts with anonymous field *T and *P.T
*T // conflicts with anonymous field T and *P.T
*P.T // conflicts with anonymous field T and *T
}
</pre>
<p>
A field or <a href="#Method_declarations">method</a> <code>f</code> of an
embedded field in a struct <code>x</code> is called <i>promoted</i> if
anonymous field in a struct <code>x</code> is called <i>promoted</i> if
<code>x.f</code> is a legal <a href="#Selectors">selector</a> that denotes
that field or method <code>f</code>.
</p>
@@ -1024,7 +1025,7 @@ promoted methods are included in the method set of the struct as follows:
</p>
<ul>
<li>
If <code>S</code> contains an embedded field <code>T</code>,
If <code>S</code> contains an anonymous field <code>T</code>,
the <a href="#Method_sets">method sets</a> of <code>S</code>
and <code>*S</code> both include promoted methods with receiver
<code>T</code>. The method set of <code>*S</code> also
@@ -1032,7 +1033,7 @@ promoted methods are included in the method set of the struct as follows:
</li>
<li>
If <code>S</code> contains an embedded field <code>*T</code>,
If <code>S</code> contains an anonymous field <code>*T</code>,
the method sets of <code>S</code> and <code>*S</code> both
include promoted methods with receiver <code>T</code> or
<code>*T</code>.
@@ -1433,8 +1434,8 @@ literal structure and corresponding components have identical types. In detail:
<li>Two struct types are identical if they have the same sequence of fields,
and if corresponding fields have the same names, and identical types,
and identical tags.
<a href="#Exported_identifiers">Non-exported</a> field names from different
packages are always different.</li>
Two anonymous fields are considered to have the same name. Lower-case field
names from different packages are always different.</li>
<li>Two pointer types are identical if they have identical base types.</li>
@@ -1444,9 +1445,8 @@ literal structure and corresponding components have identical types. In detail:
Parameter and result names are not required to match.</li>
<li>Two interface types are identical if they have the same set of methods
with the same names and identical function types.
<a href="#Exported_identifiers">Non-exported</a> method names from different
packages are always different. The order of the methods is irrelevant.</li>
with the same names and identical function types. Lower-case method names from
different packages are always different. The order of the methods is irrelevant.</li>
<li>Two map types are identical if they have identical key and value types.</li>
@@ -1891,7 +1891,7 @@ type NewMutex Mutex
type PtrMutex *Mutex
// The method set of *PrintableMutex contains the methods
// Lock and Unlock bound to its embedded field Mutex.
// Lock and Unlock bound to its anonymous field Mutex.
type PrintableMutex struct {
Mutex
}
@@ -2492,13 +2492,13 @@ If <code>x</code> is a package name, see the section on
A selector <code>f</code> may denote a field or method <code>f</code> of
a type <code>T</code>, or it may refer
to a field or method <code>f</code> of a nested
<a href="#Struct_types">embedded field</a> of <code>T</code>.
The number of embedded fields traversed
<a href="#Struct_types">anonymous field</a> of <code>T</code>.
The number of anonymous fields traversed
to reach <code>f</code> is called its <i>depth</i> in <code>T</code>.
The depth of a field or method <code>f</code>
declared in <code>T</code> is zero.
The depth of a field or method <code>f</code> declared in
an embedded field <code>A</code> in <code>T</code> is the
an anonymous field <code>A</code> in <code>T</code> is the
depth of <code>f</code> in <code>A</code> plus one.
</p>

View File

@@ -143,7 +143,7 @@ packaged Go distribution.
<p>
To build a bootstrap tool chain from source, use
either the git branch <code>release-branch.go1.4</code> or
<a href="https://storage.googleapis.com/golang/go1.4-bootstrap-20161024.tar.gz">go1.4-bootstrap-20161024.tar.gz</a>,
<a href="https://storage.googleapis.com/golang/go1.4-bootstrap-20170531.tar.gz">go1.4-bootstrap-20170531.tar.gz</a>,
which contains the Go 1.4 source code plus accumulated fixes
to keep the tools running on newer operating systems.
(Go 1.4 was the last distribution in which the tool chain was written in C.)

View File

@@ -6,7 +6,9 @@
<div class="left">
<div id="learn">
{{if not $.GoogleCN}}
<a class="popout share">Pop-out</a>
{{end}}
<div class="rootHeading">Try Go</div>
<div class="input">
<textarea spellcheck="false" class="code">// You can edit this code!
@@ -26,10 +28,10 @@ Hello, 世界
</div>
<div class="buttons">
<a class="run" href="#" title="Run this code [shift-enter]">Run</a>
{{if $.Share}}
{{if not $.GoogleCN}}
<a class="share" href="#" title="Share this code">Share</a>
{{end}}
<a class="tour" href="//tour.golang.org/" title="Learn Go from your browser">Tour</a>
{{end}}
</div>
<div class="toys">
<select>
@@ -68,85 +70,91 @@ Linux, Mac OS X, Windows, and more.
<div style="clear: both"></div>
{{if not $.GoogleCN}}
<div class="left">
<div id="video">
<div class="rootHeading">Featured video</div>
<iframe width="415" height="241" src="//www.youtube.com/embed/ytEkHepK08c" frameborder="0" allowfullscreen></iframe>
</div>
<div id="video">
<div class="rootHeading">Featured video</div>
<iframe width="415" height="241" src="//www.youtube.com/embed/ytEkHepK08c" frameborder="0" allowfullscreen></iframe>
</div>
</div>
<div class="right">
<div id="blog">
<div class="rootHeading">Featured articles</div>
<div class="read"><a href="//blog.golang.org/">Read more</a></div>
</div>
<div id="blog">
<div class="rootHeading">Featured articles</div>
<div class="read"><a href="//blog.golang.org/">Read more</a></div>
</div>
</div>
{{end}}
<div style="clear: both;"></div>
<script type="text/javascript">
<script>
(function() {
'use strict';
function readableTime(t) {
var m = ["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"];
var p = t.substring(0, t.indexOf("T")).split("-");
var d = new Date(p[0], p[1]-1, p[2]);
return d.getDate() + " " + m[d.getMonth()] + " " + d.getFullYear();
}
window.initFuncs.push(function() {
// Set up playground if enabled.
if (window.playground) {
window.playground({
"codeEl": "#learn .code",
"outputEl": "#learn .output",
"runEl": "#learn .run",
"shareEl": "#learn .share",
"shareRedirect": "//play.golang.org/p/",
"toysEl": "#learn .toys select"
});
} else {
$('#learn').hide()
}
});
function feedLoaded(result) {
var blog = document.getElementById("blog");
var read = blog.getElementsByClassName("read")[0];
for (var i = 0; i < result.length && i < 2; i++) {
var entry = result[i];
var title = document.createElement("a");
title.className = "title";
title.href = entry.Link;
title.innerHTML = entry.Title;
blog.insertBefore(title, read);
var extract = document.createElement("div");
extract.className = "extract";
extract.innerHTML = entry.Summary;
blog.insertBefore(extract, read);
var when = document.createElement("div");
when.className = "when";
when.innerHTML = "Published " + readableTime(entry.Time);
blog.insertBefore(when, read);
}
}
{{if not $.GoogleCN}}
window.initFuncs.push(function() {
// Set up playground if enabled.
if (window.playground) {
window.playground({
"codeEl": "#learn .code",
"outputEl": "#learn .output",
"runEl": "#learn .run",
"shareEl": "#learn .share",
"shareRedirect": "//play.golang.org/p/",
"toysEl": "#learn .toys select"
});
} else {
$('#learn').hide()
function readableTime(t) {
var m = ["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"];
var p = t.substring(0, t.indexOf("T")).split("-");
var d = new Date(p[0], p[1]-1, p[2]);
return d.getDate() + " " + m[d.getMonth()] + " " + d.getFullYear();
}
// Load blog feed.
$('<script/>').attr('text', 'text/javascript')
.attr('src', '//blog.golang.org/.json?jsonp=feedLoaded')
.appendTo('body');
window.feedLoaded = function(result) {
var blog = document.getElementById("blog");
var read = blog.getElementsByClassName("read")[0];
for (var i = 0; i < result.length && i < 2; i++) {
var entry = result[i];
var title = document.createElement("a");
title.className = "title";
title.href = entry.Link;
title.innerHTML = entry.Title;
blog.insertBefore(title, read);
var extract = document.createElement("div");
extract.className = "extract";
extract.innerHTML = entry.Summary;
blog.insertBefore(extract, read);
var when = document.createElement("div");
when.className = "when";
when.innerHTML = "Published " + readableTime(entry.Time);
blog.insertBefore(when, read);
}
}
// Set the video at random.
var videos = [
{h: 241, s: "//www.youtube.com/embed/ytEkHepK08c"}, // Tour of Go
{h: 241, s: "//www.youtube.com/embed/f6kdp27TYZs"}, // Concurrency Patterns
{h: 233, s: "//player.vimeo.com/video/69237265"} // Simple environment
];
var v = videos[Math.floor(Math.random()*videos.length)];
$('#video iframe').attr('height', v.h).attr('src', v.s);
});
window.initFuncs.push(function() {
// Load blog feed.
$('<script/>').attr('text', 'text/javascript')
.attr('src', '//blog.golang.org/.json?jsonp=feedLoaded')
.appendTo('body');
// Set the video at random.
var videos = [
{h: 241, s: "//www.youtube.com/embed/ytEkHepK08c"}, // Tour of Go
{h: 241, s: "//www.youtube.com/embed/f6kdp27TYZs"}, // Concurrency Patterns
{h: 233, s: "//player.vimeo.com/video/69237265"} // Simple environment
];
var v = videos[Math.floor(Math.random()*videos.length)];
$('#video iframe').attr('height', v.h).attr('src', v.s);
});
{{end}}
})();
</script>

View File

@@ -5,7 +5,7 @@
package main
/*
#cgo LDFLAGS: -c
#cgo LDFLAGS: -L/nonexist
void test() {
xxx; // ERROR HERE

View File

@@ -55,11 +55,21 @@ For example:
The default pkg-config tool may be changed by setting the PKG_CONFIG environment variable.
For security reasons, only a limited set of flags are allowed, notably -D, -I, and -l.
To allow additional flags, set CGO_CFLAGS_ALLOW to a regular expression
matching the new flags. To disallow flags that would otherwise be allowed,
set CGO_CFLAGS_DISALLOW to a regular expression matching arguments
that must be disallowed. In both cases the regular expression must match
a full argument: to allow -mfoo=bar, use CGO_CFLAGS_ALLOW='-mfoo.*',
not just CGO_CFLAGS_ALLOW='-mfoo'. Similarly named variables control
the allowed CPPFLAGS, CXXFLAGS, FFLAGS, and LDFLAGS.
When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS and
CGO_LDFLAGS environment variables are added to the flags derived from
these directives. Package-specific flags should be set using the
directives, not the environment variables, so that builds work in
unmodified environments.
unmodified environments. Flags obtained from environment variables
are not subject to the security limitations described above.
All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and
used to compile C files in that package. All the CPPFLAGS and CXXFLAGS

View File

@@ -74,13 +74,7 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
lastzero = o
}
o += w
maxwidth := Thearch.MAXWIDTH
// On 32-bit systems, reflect tables impose an additional constraint
// that each field start offset must fit in 31 bits.
if maxwidth < 1<<32 {
maxwidth = 1<<31 - 1
}
if o >= maxwidth {
if o >= Thearch.MAXWIDTH {
yyerror("type %L too large", errtype)
o = 8 // small but nonzero
}

View File

@@ -140,12 +140,11 @@ const debugFormat = false // default: false
const forceObjFileStability = true
// Current export format version. Increase with each format change.
// 4: type name objects support type aliases, uses aliasTag
// 3: Go1.8 encoding (same as version 2, aliasTag defined but never used)
// 2: removed unused bool in ODCL export (compiler only)
// 3: added aliasTag and export of aliases
// 2: removed unused bool in ODCL export
// 1: header format change (more regular), export package for _ struct fields
// 0: Go1.7 encoding
const exportVersion = 4
const exportVersion = 3
// exportInlined enables the export of inlined function bodies and related
// dependencies. The compiler should work w/o any loss of functionality with
@@ -352,8 +351,8 @@ func export(out *bufio.Writer, trace bool) int {
p.tracef("\n")
}
if sym.isAlias() {
Fatalf("exporter: unexpected type alias %v in inlined function body", sym)
if sym.Flags&SymAlias != 0 {
Fatalf("exporter: unexpected alias %v in inlined function body", sym)
}
p.obj(sym)
@@ -447,6 +446,30 @@ func unidealType(typ *Type, val Val) *Type {
}
func (p *exporter) obj(sym *Sym) {
if sym.Flags&SymAlias != 0 {
p.tag(aliasTag)
p.pos(nil) // TODO(gri) fix position information
// Aliases can only be exported from the package that
// declares them (aliases to aliases are resolved to the
// original object, and so are uses of aliases in inlined
// exported function bodies). Thus, we only need the alias
// name without package qualification.
if sym.Pkg != localpkg {
Fatalf("exporter: export of non-local alias: %v", sym)
}
p.string(sym.Name)
orig := sym.Def.Sym
if orig.Flags&SymAlias != 0 {
Fatalf("exporter: original object %v marked as alias", sym)
}
p.qualifiedName(orig)
return
}
if sym != sym.Def.Sym {
Fatalf("exporter: exported object %v is not original %v", sym, sym.Def.Sym)
}
// Exported objects may be from different packages because they
// may be re-exported via an exported alias or as dependencies in
// exported inlined function bodies. Thus, exported object names
@@ -486,13 +509,7 @@ func (p *exporter) obj(sym *Sym) {
Fatalf("exporter: export of incomplete type %v", sym)
}
if sym.isAlias() {
p.tag(aliasTag)
p.pos(n)
p.qualifiedName(sym)
} else {
p.tag(typeTag)
}
p.tag(typeTag)
p.typ(t)
case ONAME:
@@ -851,29 +868,19 @@ func (p *exporter) methodList(t *Type) {
func (p *exporter) method(m *Field) {
p.pos(m.Nname)
p.methodName(m.Sym)
p.fieldName(m)
p.paramList(m.Type.Params(), false)
p.paramList(m.Type.Results(), false)
}
// fieldName is like qualifiedName but it doesn't record the package for exported names.
func (p *exporter) fieldName(t *Field) {
name := t.Sym.Name
if t.Embedded != 0 {
// anonymous field - we distinguish between 3 cases:
// 1) field name matches base type name and is exported
// 2) field name matches base type name and is not exported
// 3) field name doesn't match base type name (alias name)
bname := basetypeName(t.Type)
if name == bname {
if exportname(name) {
name = "" // 1) we don't need to know the field name or package
} else {
name = "?" // 2) use unexported name "?" to force package export
}
} else {
// 3) indicate alias and export name as is
// (this requires an extra "@" but this is a rare case)
p.string("@")
name = "" // anonymous field
if bname := basetypeName(t.Type); bname != "" && !exportname(bname) {
// anonymous field with unexported base type name
name = "?" // unexported name to force export of package
}
}
p.string(name)
@@ -882,23 +889,16 @@ func (p *exporter) fieldName(t *Field) {
}
}
// methodName is like qualifiedName but it doesn't record the package for exported names.
func (p *exporter) methodName(sym *Sym) {
p.string(sym.Name)
if !exportname(sym.Name) {
p.pkg(sym.Pkg)
}
}
func basetypeName(t *Type) string {
s := t.Sym
if s == nil && t.IsPtr() {
s = t.Elem().Sym // deref
}
// s should exist, but be conservative
if s != nil {
return s.Name
}
return "" // unnamed type
return ""
}
func (p *exporter) paramList(params *Type, numbered bool) {
@@ -1797,7 +1797,7 @@ const (
nilTag
unknownTag // not used by gc (only appears in packages with errors)
// Type aliases
// Aliases
aliasTag
)
@@ -1835,7 +1835,7 @@ var tagString = [...]string{
-nilTag: "nil",
-unknownTag: "unknown",
// Type aliases
// Aliases
-aliasTag: "alias",
}
@@ -1889,7 +1889,7 @@ func predeclared() []*Type {
Types[TCOMPLEX128],
Types[TSTRING],
// basic type aliases
// aliases
bytetype,
runetype,

View File

@@ -86,10 +86,10 @@ func Import(in *bufio.Reader) {
// read version specific flags - extend as necessary
switch p.version {
// case 5:
// case 4:
// ...
// fallthrough
case 4, 3, 2, 1:
case 3, 2, 1:
p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
p.trackAllTypes = p.bool()
p.posInfoFormat = p.bool()
@@ -317,12 +317,6 @@ func (p *importer) obj(tag int) {
val := p.value(typ)
importconst(sym, idealType(typ), nodlit(val))
case aliasTag:
p.pos()
sym := p.qualifiedName()
typ := p.typ()
importalias(sym, typ)
case typeTag:
p.typ()
@@ -362,6 +356,17 @@ func (p *importer) obj(tag int) {
}
}
case aliasTag:
p.pos()
alias := importpkg.Lookup(p.string())
orig := p.qualifiedName()
// Although the protocol allows the alias to precede the original,
// this never happens in files produced by gc.
alias.Flags |= SymAlias
alias.Def = orig.Def
importsym(alias, orig.Def.Op)
default:
formatErrorf("unexpected object (tag = %d)", tag)
}
@@ -468,7 +473,14 @@ func (p *importer) typ() *Type {
result := p.paramList()
nointerface := p.bool()
n := newfuncname(methodname(sym, recv[0].Type))
base := recv[0].Type
star := false
if base.IsPtr() {
base = base.Elem()
star = true
}
n := methodname0(sym, star, base.Sym)
n.Type = functypefield(recv[0], params, result)
checkwidth(n.Type)
addmethod(sym, n.Type, false, nointerface)
@@ -571,22 +583,19 @@ func (p *importer) fieldList() (fields []*Field) {
func (p *importer) field() *Field {
p.pos()
sym, alias := p.fieldName()
sym := p.fieldName()
typ := p.typ()
note := p.string()
f := newField()
if sym.Name == "" {
// anonymous field: typ must be T or *T and T must be a type name
// anonymous field - typ must be T or *T and T must be a type name
s := typ.Sym
if s == nil && typ.IsPtr() {
s = typ.Elem().Sym // deref
}
sym = sym.Pkg.Lookup(s.Name)
f.Embedded = 1
} else if alias {
// anonymous field: we have an explicit name because it's a type alias
f.Embedded = 1
}
f.Sym = sym
@@ -609,7 +618,7 @@ func (p *importer) methodList() (methods []*Field) {
func (p *importer) method() *Field {
p.pos()
sym := p.methodName()
sym := p.fieldName()
params := p.paramList()
result := p.paramList()
@@ -620,44 +629,18 @@ func (p *importer) method() *Field {
return f
}
func (p *importer) fieldName() (*Sym, bool) {
func (p *importer) fieldName() *Sym {
name := p.string()
if p.version == 0 && name == "_" {
// version 0 didn't export a package for _ field names
// but used the builtin package instead
return builtinpkg.Lookup(name), false
}
pkg := localpkg
alias := false
switch name {
case "":
// 1) field name matches base type name and is exported: nothing to do
case "?":
// 2) field name matches base type name and is not exported: need package
name = ""
pkg = p.pkg()
case "@":
// 3) field name doesn't match base type name (alias name): need name and possibly package
name = p.string()
alias = true
fallthrough
default:
if !exportname(name) {
pkg = p.pkg()
}
}
return pkg.Lookup(name), alias
}
func (p *importer) methodName() *Sym {
name := p.string()
if p.version == 0 && name == "_" {
// version 0 didn't export a package for _ method names
// version 0 didn't export a package for _ fields
// but used the builtin package instead
return builtinpkg.Lookup(name)
}
pkg := localpkg
if !exportname(name) {
if name != "" && !exportname(name) {
if name == "?" {
name = ""
}
pkg = p.pkg()
}
return pkg.Lookup(name)

View File

@@ -519,6 +519,10 @@ func funchdr(n *Node) {
Fatalf("funchdr: dclcontext = %d", dclcontext)
}
if Ctxt.Flag_dynlink && importpkg == nil && n.Func.Nname != nil {
makefuncsym(n.Func.Nname.Sym)
}
dclcontext = PAUTO
funcstart(n)
@@ -691,20 +695,10 @@ func typedcl0(s *Sym) *Node {
// node n, which was returned by typedcl0
// is being declared to have uncompiled type t.
// returns the ODCLTYPE node to use.
func typedcl1(n *Node, t *Node, pragma Pragma, alias bool) *Node {
if pragma != 0 && alias {
yyerror("cannot specify directive with type alias")
pragma = 0
}
n.Local = true
p := n.Name.Param
p.Ntype = t
p.Pragma = pragma
p.Alias = alias
// return the ODCLTYPE node to use.
func typedcl1(n *Node, t *Node, local bool) *Node {
n.Name.Param.Ntype = t
n.Local = local
return nod(ODCLTYPE, n, nil)
}
@@ -1159,19 +1153,19 @@ bad:
return nil
}
// methodname is a misnomer because this now returns a Sym, rather
// than an ONAME.
// TODO(mdempsky): Reconcile with methodsym.
func methodname(s *Sym, recv *Type) *Sym {
func methodname(n *Node, t *Node) *Node {
star := false
if recv.IsPtr() {
if t.Op == OIND {
star = true
recv = recv.Elem()
t = t.Left
}
tsym := recv.Sym
return methodname0(n.Sym, star, t.Sym)
}
func methodname0(s *Sym, star bool, tsym *Sym) *Node {
if tsym == nil || isblanksym(s) {
return s
return newfuncname(s)
}
var p string
@@ -1187,13 +1181,14 @@ func methodname(s *Sym, recv *Type) *Sym {
s = Pkglookup(p, tsym.Pkg)
}
return s
return newfuncname(s)
}
// Add a method, declared as a function.
// - msym is the method symbol
// - t is function type (with receiver)
func addmethod(msym *Sym, t *Type, local, nointerface bool) {
// get field sym
if msym == nil {
Fatalf("no method symbol")
}
@@ -1314,7 +1309,7 @@ func funcsym(s *Sym) *Sym {
s1 := Pkglookup(s.Name+"·f", s.Pkg)
if !Ctxt.Flag_dynlink && s1.Def == nil {
s1.Def = newfuncname(s1)
s1.Def.Func.Shortname = s
s1.Def.Func.Shortname = newname(s)
funcsyms = append(funcsyms, s1.Def)
}
s.Fsym = s1
@@ -1331,11 +1326,8 @@ func makefuncsym(s *Sym) {
return
}
s1 := funcsym(s)
if s1.Def != nil {
return
}
s1.Def = newfuncname(s1)
s1.Def.Func.Shortname = s
s1.Def.Func.Shortname = newname(s)
funcsyms = append(funcsyms, s1.Def)
}

View File

@@ -45,8 +45,8 @@ func exportsym(n *Node) {
fmt.Printf("export symbol %v\n", n.Sym)
}
// Ensure original types are on exportlist before type aliases.
if n.Sym.isAlias() {
// Ensure original object is on exportlist before aliases.
if n.Sym.Flags&SymAlias != 0 {
exportlist = append(exportlist, n.Sym.Def)
}
@@ -83,7 +83,7 @@ func autoexport(n *Node, ctxt Class) {
if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
return
}
if n.Type != nil && n.Type.IsKind(TFUNC) && n.Type.Recv() != nil { // method
if n.Name.Param != nil && n.Name.Param.Ntype != nil && n.Name.Param.Ntype.Op == OTFUNC && n.Name.Param.Ntype.Left != nil { // method
return
}
@@ -348,27 +348,6 @@ func importvar(s *Sym, t *Type) {
}
}
// importalias declares symbol s as an imported type alias with type t.
func importalias(s *Sym, t *Type) {
importsym(s, OTYPE)
if s.Def != nil && s.Def.Op == OTYPE {
if eqtype(t, s.Def.Type) {
return
}
yyerror("inconsistent definition for type alias %v during import\n\t%v (in %q)\n\t%v (in %q)", s, s.Def.Type, s.Importdef.Path, t, importpkg.Path)
}
n := newname(s)
n.Op = OTYPE
s.Importdef = importpkg
n.Type = t
declare(n, PEXTERN)
if Debug['E'] != 0 {
fmt.Printf("import type %v = %L\n", s, t)
}
}
func dumpasmhdr() {
b, err := bio.Create(asmhdr)
if err != nil {

View File

@@ -1077,7 +1077,6 @@ var opprec = []int{
OSEND: 3,
OANDAND: 2,
OOROR: 1,
// Statements handled by stmtfmt
OAS: -1,
OAS2: -1,
@@ -1105,8 +1104,7 @@ var opprec = []int{
OSWITCH: -1,
OXCASE: -1,
OXFALL: -1,
OEND: 0,
OEND: 0,
}
func (n *Node) exprfmt(s fmt.State, prec int) {

View File

@@ -63,12 +63,9 @@ const (
SymSiggen
SymAsm
SymAlgGen
SymAlias // alias, original is Sym.Def.Sym
)
func (sym *Sym) isAlias() bool {
return sym.Def != nil && sym.Def.Sym != sym
}
// The Class of a variable/function describes the "storage class"
// of a variable or function. During parsing, storage classes are
// called declaration contexts.
@@ -90,7 +87,7 @@ const (
// of the compilers arrays.
//
// typedef struct
// { // must not move anything
// { // must not move anything
// uchar array[8]; // pointer to data
// uchar nel[4]; // number of elements
// uchar cap[4]; // allocated number of elements
@@ -107,7 +104,7 @@ var sizeof_Array int // runtime sizeof(Array)
// of the compilers strings.
//
// typedef struct
// { // must not move anything
// { // must not move anything
// uchar array[8]; // pointer to data
// uchar nel[4]; // number of elements
// } String;
@@ -251,6 +248,7 @@ var nblank *Node
var typecheckok bool
var compiling_runtime bool
var compiling_std bool
var compiling_wrappers int

View File

@@ -154,6 +154,7 @@ func Main() {
}
flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
obj.Flagcount("B", "disable bounds checking", &Debug['B'])
flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
@@ -340,16 +341,13 @@ func Main() {
// Phase 1: const, type, and names and types of funcs.
// This will gather all the information about types
// and methods but doesn't depend on any of it.
// We also defer type alias declarations until phase 2
// to avoid cycles like #18640.
defercheckwidth()
// Don't use range--typecheck can add closures to xtop.
timings.Start("fe", "typecheck", "top1")
for i := 0; i < len(xtop); i++ {
n := xtop[i]
if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
xtop[i] = typecheck(n, Etop)
if xtop[i].Op != ODCL && xtop[i].Op != OAS && xtop[i].Op != OAS2 {
xtop[i] = typecheck(xtop[i], Etop)
}
}
@@ -359,9 +357,8 @@ func Main() {
// Don't use range--typecheck can add closures to xtop.
timings.Start("fe", "typecheck", "top2")
for i := 0; i < len(xtop); i++ {
n := xtop[i]
if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
xtop[i] = typecheck(n, Etop)
if xtop[i].Op == ODCL || xtop[i].Op == OAS || xtop[i].Op == OAS2 {
xtop[i] = typecheck(xtop[i], Etop)
}
}
resumecheckwidth()
@@ -371,9 +368,8 @@ func Main() {
timings.Start("fe", "typecheck", "func")
var fcount int64
for i := 0; i < len(xtop); i++ {
n := xtop[i]
if op := n.Op; op == ODCLFUNC || op == OCLOSURE {
Curfn = n
if xtop[i].Op == ODCLFUNC || xtop[i].Op == OCLOSURE {
Curfn = xtop[i]
decldepth = 1
saveerrors()
typecheckslice(Curfn.Nbody.Slice(), Etop)
@@ -465,9 +461,8 @@ func Main() {
timings.Start("be", "compilefuncs")
fcount = 0
for i := 0; i < len(xtop); i++ {
n := xtop[i]
if n.Op == ODCLFUNC {
funccompile(n)
if xtop[i].Op == ODCLFUNC {
funccompile(xtop[i])
fcount++
}
}
@@ -930,7 +925,7 @@ func mkpackage(pkgname string) {
continue
}
if s.isAlias() {
if s.Def.Sym != s && s.Flags&SymAlias == 0 {
// throw away top-level name left over
// from previous import . "x"
if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {

View File

@@ -7,6 +7,7 @@ package gc
import (
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"unicode/utf8"
@@ -154,7 +155,11 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
func (p *noder) varDecl(decl *syntax.VarDecl) []*Node {
names := p.declNames(decl.NameList)
typ := p.typeExprOrNil(decl.Type)
var typ *Node
if decl.Type != nil {
typ = p.typeExpr(decl.Type)
}
var exprs []*Node
if decl.Values != nil {
@@ -167,7 +172,11 @@ func (p *noder) varDecl(decl *syntax.VarDecl) []*Node {
func (p *noder) constDecl(decl *syntax.ConstDecl) []*Node {
names := p.declNames(decl.NameList)
typ := p.typeExprOrNil(decl.Type)
var typ *Node
if decl.Type != nil {
typ = p.typeExpr(decl.Type)
}
var exprs []*Node
if decl.Values != nil {
@@ -179,11 +188,14 @@ func (p *noder) constDecl(decl *syntax.ConstDecl) []*Node {
func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
name := typedcl0(p.name(decl.Name))
name.Name.Param.Pragma = Pragma(decl.Pragma)
// decl.Type may be nil but in that case we got a syntax error during parsing
typ := p.typeExprOrNil(decl.Type)
var typ *Node
if decl.Type != nil {
typ = p.typeExpr(decl.Type)
}
return typedcl1(name, typ, Pragma(decl.Pragma), decl.Alias)
return typedcl1(name, typ, true)
}
func (p *noder) declNames(names []*syntax.Name) []*Node {
@@ -248,19 +260,19 @@ func (p *noder) funcHeader(fun *syntax.FuncDecl) *Node {
yyerror("func main must have no arguments and no return values")
}
}
f.Func.Nname = newfuncname(name)
} else {
f.Func.Shortname = name
name = nblank.Sym // filled in by typecheckfunc
// Receiver MethodName Signature
f.Func.Shortname = newfuncname(name)
f.Func.Nname = methodname(f.Func.Shortname, t.Left.Right)
}
f.Func.Nname = newfuncname(name)
f.Func.Nname.Name.Defn = f
f.Func.Nname.Name.Param.Ntype = t // TODO: check if nname already has an ntype
if fun.Recv == nil {
declare(f.Func.Nname, PFUNC)
}
declare(f.Func.Nname, PFUNC)
funchdr(f)
return f
}
@@ -456,13 +468,6 @@ func (p *noder) typeExpr(typ syntax.Expr) *Node {
return p.expr(typ)
}
func (p *noder) typeExprOrNil(typ syntax.Expr) *Node {
if typ != nil {
return p.expr(typ)
}
return nil
}
func (p *noder) chanDir(dir syntax.ChanDir) ChanDir {
switch dir {
case 0:
@@ -1053,6 +1058,11 @@ func (p *noder) pragma(pos, line int, text string) syntax.Pragma {
case strings.HasPrefix(text, "go:cgo_"):
lineno = p.baseline + int32(line) - 1 // pragcgo may call yyerror
// For security, we disallow //go:cgo_* directives outside cgo-generated files.
// Exception: they are allowed in the standard library, for runtime and syscall.
if !isCgoGeneratedFile() && !compiling_std {
p.error(syntax.Error{Pos: pos, Line: line, Msg: fmt.Sprintf("//%s only allowed in cgo-generated code", text)})
}
pragcgobuf += pragcgo(text)
fallthrough // because of //go:cgo_unsafe_args
default:
@@ -1067,6 +1077,20 @@ func (p *noder) pragma(pos, line int, text string) syntax.Pragma {
return 0
}
// isCgoGeneratedFile reports whether lineno is in a file
// generated by cgo, which is to say a file with name
// beginning with "_cgo_". Such files are allowed to
// contain cgo directives, and for security reasons
// (primarily misuse of linker flags), other files are not.
// See golang.org/issue/23672.
func isCgoGeneratedFile() bool {
stk := Ctxt.LineHist.At(int(lineno))
if stk == nil {
return false
}
return strings.HasPrefix(filepath.Base(filepath.Clean(stk.File)), "_cgo_")
}
func mkname(sym *Sym) *Node {
n := oldname(sym)
if n.Name != nil && n.Name.Pack != nil {

View File

@@ -213,7 +213,7 @@ func dumpglobls() {
}
for _, n := range funcsyms {
dsymptr(n.Sym, 0, n.Sym.Def.Func.Shortname, 0)
dsymptr(n.Sym, 0, n.Sym.Def.Func.Shortname.Sym, 0)
ggloblsym(n.Sym, int32(Widthptr), obj.DUPOK|obj.RODATA)
}

View File

@@ -511,7 +511,7 @@ func isExportedField(ft *Field) (bool, *Pkg) {
// dnameField dumps a reflect.name for a struct field.
func dnameField(s *Sym, ot int, spkg *Pkg, ft *Field) int {
var name string
if ft.Sym != nil {
if ft.Sym != nil && ft.Embedded == 0 {
name = ft.Sym.Name
}
isExported, fpkg := isExportedField(ft)
@@ -1345,14 +1345,7 @@ ok:
// ../../../../runtime/type.go:/structField
ot = dnameField(s, ot, pkg, f)
ot = dsymptr(s, ot, dtypesym(f.Type), 0)
offsetAnon := uint64(f.Offset) << 1
if offsetAnon>>1 != uint64(f.Offset) {
Fatalf("%v: bad field offset for %s", t, f.Sym.Name)
}
if f.Embedded != 0 {
offsetAnon |= 1
}
ot = duintptr(s, ot, offsetAnon)
ot = duintptr(s, ot, uint64(f.Offset))
}
}

View File

@@ -27,7 +27,7 @@ type Node struct {
// func
Func *Func
// ONAME, OTYPE, OPACK, OLABEL, some OLITERAL
// ONAME
Name *Name
Sym *Sym // various
@@ -59,8 +59,8 @@ type Node struct {
Noescape bool // func arguments do not escape; TODO(rsc): move Noescape to Func struct (see CL 7360)
Walkdef uint8 // tracks state during typecheckdef; 2 == loop detected
Typecheck uint8 // tracks state during typechecking; 2 == loop detected
Local bool // type created in this file (see also Type.Local); TODO(gri): move this into flags
IsStatic bool // whether this Node will be converted to purely static data
Local bool
IsStatic bool // whether this Node will be converted to purely static data
Initorder uint8
Used bool // for variable/label declared and not used error
Isddd bool // is the argument variadic
@@ -180,14 +180,14 @@ func (n *Node) SetIota(x int64) {
n.Xoffset = x
}
// Name holds Node fields used only by named nodes (ONAME, OTYPE, OPACK, OLABEL, some OLITERAL).
// Name holds Node fields used only by named nodes (ONAME, OPACK, OLABEL, some OLITERAL).
type Name struct {
Pack *Node // real package for import . names
Pkg *Pkg // pkg for OPACK nodes
Heapaddr *Node // temp holding heap address of param (could move to Param?)
Defn *Node // initializing assignment
Curfn *Node // function for local variables
Param *Param // additional fields for ONAME, OTYPE
Param *Param // additional fields for ONAME
Decldepth int32 // declaration loop depth, increased for every loop or label
Vargen int32 // unique name for ONAME within a function. Function outputs are numbered starting at one.
Funcdepth int32
@@ -280,16 +280,15 @@ type Param struct {
Innermost *Node
Outer *Node
// OTYPE
// OTYPE pragmas
//
// TODO: Should Func pragmas also be stored on the Name?
Pragma Pragma
Alias bool // node is alias for Ntype (only used when type-checking ODCLTYPE)
}
// Func holds Node fields used only with function-like nodes.
type Func struct {
Shortname *Sym
Shortname *Node
Enter Nodes // for example, allocate and initialize memory for escaping parameters
Exit Nodes
Cvars Nodes // closure params
@@ -383,7 +382,7 @@ const (
ODCLFUNC // func f() or func (r) f()
ODCLFIELD // struct field, interface field, or func/method argument/return value.
ODCLCONST // const pi = 3.14
ODCLTYPE // type Int int or type Int = int
ODCLTYPE // type Int int
ODELETE // delete(Left, Right)
ODOT // Left.Sym (Left is of struct type)

View File

@@ -102,12 +102,120 @@ func testDeadStorePanic() {
}
}
//go:noinline
func loadHitStore8(x int8, p *int8) int32 {
x *= x // try to trash high bits (arch-dependent)
*p = x // store
return int32(*p) // load and cast
}
//go:noinline
func loadHitStoreU8(x uint8, p *uint8) uint32 {
x *= x // try to trash high bits (arch-dependent)
*p = x // store
return uint32(*p) // load and cast
}
//go:noinline
func loadHitStore16(x int16, p *int16) int32 {
x *= x // try to trash high bits (arch-dependent)
*p = x // store
return int32(*p) // load and cast
}
//go:noinline
func loadHitStoreU16(x uint16, p *uint16) uint32 {
x *= x // try to trash high bits (arch-dependent)
*p = x // store
return uint32(*p) // load and cast
}
//go:noinline
func loadHitStore32(x int32, p *int32) int64 {
x *= x // try to trash high bits (arch-dependent)
*p = x // store
return int64(*p) // load and cast
}
//go:noinline
func loadHitStoreU32(x uint32, p *uint32) uint64 {
x *= x // try to trash high bits (arch-dependent)
*p = x // store
return uint64(*p) // load and cast
}
func testLoadHitStore() {
// Test that sign/zero extensions are kept when a load-hit-store
// is replaced by a register-register move.
{
var in int8 = (1 << 6) + 1
var p int8
got := loadHitStore8(in, &p)
want := int32(in * in)
if got != want {
fmt.Println("testLoadHitStore (int8) failed. want =", want, ", got =", got)
failed = true
}
}
{
var in uint8 = (1 << 6) + 1
var p uint8
got := loadHitStoreU8(in, &p)
want := uint32(in * in)
if got != want {
fmt.Println("testLoadHitStore (uint8) failed. want =", want, ", got =", got)
failed = true
}
}
{
var in int16 = (1 << 10) + 1
var p int16
got := loadHitStore16(in, &p)
want := int32(in * in)
if got != want {
fmt.Println("testLoadHitStore (int16) failed. want =", want, ", got =", got)
failed = true
}
}
{
var in uint16 = (1 << 10) + 1
var p uint16
got := loadHitStoreU16(in, &p)
want := uint32(in * in)
if got != want {
fmt.Println("testLoadHitStore (uint16) failed. want =", want, ", got =", got)
failed = true
}
}
{
var in int32 = (1 << 30) + 1
var p int32
got := loadHitStore32(in, &p)
want := int64(in * in)
if got != want {
fmt.Println("testLoadHitStore (int32) failed. want =", want, ", got =", got)
failed = true
}
}
{
var in uint32 = (1 << 30) + 1
var p uint32
got := loadHitStoreU32(in, &p)
want := uint64(in * in)
if got != want {
fmt.Println("testLoadHitStore (uint32) failed. want =", want, ", got =", got)
failed = true
}
}
}
func main() {
testLoadStoreOrder()
testStoreSize()
testExtStore()
testDeadStorePanic()
testLoadHitStore()
if failed {
panic("failed")

View File

@@ -96,16 +96,16 @@ func typekind(t *Type) string {
return fmt.Sprintf("etype=%d", et)
}
// sprint_depchain prints a dependency chain of nodes into trace.
// sprint_depchain prints a dependency chain of nodes into fmt.
// It is used by typecheck in the case of OLITERAL nodes
// to print constant definition loops.
func sprint_depchain(trace *string, stack []*Node, cur *Node, first *Node) {
func sprint_depchain(fmt_ *string, stack []*Node, cur *Node, first *Node) {
for i := len(stack) - 1; i >= 0; i-- {
if n := stack[i]; n.Op == cur.Op {
if n != first {
sprint_depchain(trace, stack[:i], n, first)
sprint_depchain(fmt_, stack[:i], n, first)
}
*trace += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cur)
*fmt_ += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cur)
return
}
}
@@ -152,6 +152,7 @@ func typecheck(n *Node, top int) *Node {
if n.Typecheck == 2 {
// Typechecking loop. Trying printing a meaningful message,
// otherwise a stack trace of typechecking.
var fmt_ string
switch n.Op {
// We can already diagnose variables used as types.
case ONAME:
@@ -159,30 +160,22 @@ func typecheck(n *Node, top int) *Node {
yyerror("%v is not a type", n)
}
case OTYPE:
if top&Etype == Etype {
var trace string
sprint_depchain(&trace, typecheck_tcstack, n, n)
yyerrorl(n.Lineno, "invalid recursive type alias %v%s", n, trace)
}
case OLITERAL:
if top&(Erv|Etype) == Etype {
yyerror("%v is not a type", n)
break
}
var trace string
sprint_depchain(&trace, typecheck_tcstack, n, n)
yyerrorl(n.Lineno, "constant definition loop%s", trace)
sprint_depchain(&fmt_, typecheck_tcstack, n, n)
yyerrorl(n.Lineno, "constant definition loop%s", fmt_)
}
if nsavederrors+nerrors == 0 {
var trace string
fmt_ = ""
for i := len(typecheck_tcstack) - 1; i >= 0; i-- {
x := typecheck_tcstack[i]
trace += fmt.Sprintf("\n\t%v %v", x.Line(), x)
fmt_ += fmt.Sprintf("\n\t%v %v", x.Line(), x)
}
yyerror("typechecking loop involving %v%s", n, trace)
yyerror("typechecking loop involving %v%s", n, fmt_)
}
lineno = lno
@@ -3435,14 +3428,7 @@ func typecheckfunc(n *Node) {
t.SetNname(n.Func.Nname)
rcvr := t.Recv()
if rcvr != nil && n.Func.Shortname != nil {
n.Func.Nname.Sym = methodname(n.Func.Shortname, rcvr.Type)
declare(n.Func.Nname, PFUNC)
addmethod(n.Func.Shortname, t, true, n.Func.Pragma&Nointerface != 0)
}
if Ctxt.Flag_dynlink && importpkg == nil && n.Func.Nname != nil {
makefuncsym(n.Func.Nname.Sym)
addmethod(n.Func.Shortname.Sym, t, true, n.Func.Pragma&Nointerface != 0)
}
}
@@ -3591,6 +3577,8 @@ func typecheckdeftype(n *Node) {
// copy new type and clear fields
// that don't come along.
// anything zeroed here must be zeroed in
// typedcl2 too.
copytype(n, t)
ret:
@@ -3769,29 +3757,12 @@ func typecheckdef(n *Node) *Node {
n.Name.Defn = typecheck(n.Name.Defn, Etop) // fills in n->type
case OTYPE:
if p := n.Name.Param; p.Alias {
// Type alias declaration: Simply use the rhs type - no need
// to create a new type.
// If we have a syntax error, p.Ntype may be nil.
if p.Ntype != nil {
p.Ntype = typecheck(p.Ntype, Etype)
n.Type = p.Ntype.Type
if n.Type == nil {
n.Diag = true
goto ret
}
n.Sym.Def = p.Ntype
}
break
}
// regular type declaration
if Curfn != nil {
defercheckwidth()
}
n.Walkdef = 1
n.Type = typ(TFORW)
n.Type.Sym = n.Sym // TODO(gri) this also happens in typecheckdeftype(n) - where should it happen?
n.Type.Sym = n.Sym
nerrors0 := nerrors
typecheckdeftype(n)
if n.Type.Etype == TFORW && nerrors > nerrors0 {
@@ -3799,6 +3770,7 @@ func typecheckdef(n *Node) *Node {
// but it was reported. Silence future errors.
n.Type.Broke = true
}
if Curfn != nil {
resumecheckwidth()
}

View File

@@ -398,14 +398,6 @@ func lexinit1() {
// errortype.Orig = makeErrorInterface()
s.Def = typenod(errortype)
// We create separate byte and rune types for better error messages
// rather than just creating type alias *Sym's for the uint8 and
// int32 types. Hence, (bytetype|runtype).Sym.isAlias() is false.
// TODO(gri) Should we get rid of this special case (at the cost
// of less informative error messages involving bytes and runes)?
// (Alternatively, we could introduce an OTALIAS node representing
// type aliases, albeit at the cost of having to deal with it everywhere).
// byte alias
s = Pkglookup("byte", builtinpkg)
bytetype = typ(TUINT8)

View File

@@ -620,10 +620,12 @@
(MOVWLZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
(MOVWLZX x:(MOVWloadidx2 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem)
// replace load from same location as preceding store with copy
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBLZX x)
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWLZX x)
(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVBLSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBLSX x)
(MOVWLSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWLSX x)
// Fold extensions and ANDs together.
(MOVBLZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xff] x)

View File

@@ -762,11 +762,14 @@
(MOVLQZX x:(MOVLloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx1 <v.Type> [off] {sym} ptr idx mem)
(MOVLQZX x:(MOVLloadidx4 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx4 <v.Type> [off] {sym} ptr idx mem)
// replace load from same location as preceding store with copy
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBQZX x)
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWQZX x)
(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVLQZX x)
(MOVQload [off] {sym} ptr (MOVQstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVBQSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBQSX x)
(MOVWQSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWQSX x)
(MOVLQSXload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVLQSX x)
// Fold extensions and ANDs together.
(MOVBQZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xff] x)

View File

@@ -467,12 +467,13 @@
(MOVDstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
// replace load from same location as preceding store with copy
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBreg x)
(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBUreg x)
(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHreg x)
(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHUreg x)
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVFload [off] {sym} ptr (MOVFstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x

View File

@@ -679,14 +679,14 @@
(MOVWstore [off] {sym} ptr (MOVDconst [0]) mem) -> (MOVWstorezero [off] {sym} ptr mem)
(MOVDstore [off] {sym} ptr (MOVDconst [0]) mem) -> (MOVDstorezero [off] {sym} ptr mem)
// replace load from same location as preceding store with copy
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
// these seem to have bad interaction with other rules, resulting in slower code
//(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
//(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
//(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
//(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
//(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
//(MOVWUload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
//(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBreg x)
//(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBUreg x)
//(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHreg x)
//(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHUreg x)
//(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWreg x)
//(MOVWUload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWUreg x)
//(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
//(FMOVSload [off] {sym} ptr (FMOVSstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
//(FMOVDload [off] {sym} ptr (FMOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x

View File

@@ -522,11 +522,11 @@
(MOVWstorezero [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
// replace load from same location as preceding store with copy
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBreg x)
(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBUreg x)
(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHreg x)
(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHUreg x)
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVFload [off] {sym} ptr (MOVFstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x

View File

@@ -656,9 +656,9 @@
(MOVWZreg x:(MOVWZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZloadidx <v.Type> [off] {sym} ptr idx mem)
// replace load from same location as preceding store with copy
(MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
(MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
(MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
(MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBZreg x)
(MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHZreg x)
(MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWZreg x)
(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
// Don't extend before storing

View File

@@ -2503,6 +2503,28 @@ func rewriteValue386_Op386MOVBLSX(v *Value, config *Config) bool {
func rewriteValue386_Op386MOVBLSXload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVBLSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVBLSX x)
for {
off := v.AuxInt
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != Op386MOVBstore {
break
}
off2 := v_1.AuxInt
sym2 := v_1.Aux
ptr2 := v_1.Args[0]
x := v_1.Args[1]
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(Op386MOVBLSX)
v.AddArg(x)
return true
}
// match: (MOVBLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
// result: (MOVBLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
@@ -2606,7 +2628,7 @@ func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
_ = b
// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: x
// result: (MOVBLZX x)
for {
off := v.AuxInt
sym := v.Aux
@@ -2622,8 +2644,7 @@ func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(Op386MOVBLZX)
v.AddArg(x)
return true
}
@@ -5248,6 +5269,28 @@ func rewriteValue386_Op386MOVWLSX(v *Value, config *Config) bool {
func rewriteValue386_Op386MOVWLSXload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVWLSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVWLSX x)
for {
off := v.AuxInt
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != Op386MOVWstore {
break
}
off2 := v_1.AuxInt
sym2 := v_1.Aux
ptr2 := v_1.Args[0]
x := v_1.Args[1]
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(Op386MOVWLSX)
v.AddArg(x)
return true
}
// match: (MOVWLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
// result: (MOVWLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
@@ -5378,7 +5421,7 @@ func rewriteValue386_Op386MOVWload(v *Value, config *Config) bool {
_ = b
// match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: x
// result: (MOVWLZX x)
for {
off := v.AuxInt
sym := v.Aux
@@ -5394,8 +5437,7 @@ func rewriteValue386_Op386MOVWload(v *Value, config *Config) bool {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(Op386MOVWLZX)
v.AddArg(x)
return true
}

View File

@@ -3361,6 +3361,28 @@ func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
func rewriteValueAMD64_OpAMD64MOVBQSXload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVBQSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVBQSX x)
for {
off := v.AuxInt
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpAMD64MOVBstore {
break
}
off2 := v_1.AuxInt
sym2 := v_1.Aux
ptr2 := v_1.Args[0]
x := v_1.Args[1]
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpAMD64MOVBQSX)
v.AddArg(x)
return true
}
// match: (MOVBQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
// result: (MOVBQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
@@ -3539,7 +3561,7 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
_ = b
// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: x
// result: (MOVBQZX x)
for {
off := v.AuxInt
sym := v.Aux
@@ -3555,8 +3577,7 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpAMD64MOVBQZX)
v.AddArg(x)
return true
}
@@ -4834,6 +4855,28 @@ func rewriteValueAMD64_OpAMD64MOVLQSX(v *Value, config *Config) bool {
func rewriteValueAMD64_OpAMD64MOVLQSXload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVLQSXload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVLQSX x)
for {
off := v.AuxInt
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpAMD64MOVLstore {
break
}
off2 := v_1.AuxInt
sym2 := v_1.Aux
ptr2 := v_1.Args[0]
x := v_1.Args[1]
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpAMD64MOVLQSX)
v.AddArg(x)
return true
}
// match: (MOVLQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
// result: (MOVLQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
@@ -5041,7 +5084,7 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
_ = b
// match: (MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: x
// result: (MOVLQZX x)
for {
off := v.AuxInt
sym := v.Aux
@@ -5057,8 +5100,7 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpAMD64MOVLQZX)
v.AddArg(x)
return true
}
@@ -8703,6 +8745,28 @@ func rewriteValueAMD64_OpAMD64MOVWQSX(v *Value, config *Config) bool {
func rewriteValueAMD64_OpAMD64MOVWQSXload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVWQSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVWQSX x)
for {
off := v.AuxInt
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpAMD64MOVWstore {
break
}
off2 := v_1.AuxInt
sym2 := v_1.Aux
ptr2 := v_1.Args[0]
x := v_1.Args[1]
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpAMD64MOVWQSX)
v.AddArg(x)
return true
}
// match: (MOVWQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
// result: (MOVWQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
@@ -8883,7 +8947,7 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
_ = b
// match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: x
// result: (MOVWQZX x)
for {
off := v.AuxInt
sym := v.Aux
@@ -8899,8 +8963,7 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpAMD64MOVWQZX)
v.AddArg(x)
return true
}

View File

@@ -5188,8 +5188,8 @@ func rewriteValueARM_OpARMMOVBUload(v *Value, config *Config) bool {
return true
}
// match: (MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
// result: x
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVBUreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -5202,11 +5202,10 @@ func rewriteValueARM_OpARMMOVBUload(v *Value, config *Config) bool {
sym2 := v_1.Aux
ptr2 := v_1.Args[0]
x := v_1.Args[1]
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpARMMOVBUreg)
v.AddArg(x)
return true
}
@@ -5317,8 +5316,8 @@ func rewriteValueARM_OpARMMOVBload(v *Value, config *Config) bool {
return true
}
// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
// result: x
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVBreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -5331,11 +5330,10 @@ func rewriteValueARM_OpARMMOVBload(v *Value, config *Config) bool {
sym2 := v_1.Aux
ptr2 := v_1.Args[0]
x := v_1.Args[1]
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpARMMOVBreg)
v.AddArg(x)
return true
}
@@ -5836,8 +5834,8 @@ func rewriteValueARM_OpARMMOVHUload(v *Value, config *Config) bool {
return true
}
// match: (MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
// result: x
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVHUreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -5850,11 +5848,10 @@ func rewriteValueARM_OpARMMOVHUload(v *Value, config *Config) bool {
sym2 := v_1.Aux
ptr2 := v_1.Args[0]
x := v_1.Args[1]
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpARMMOVHUreg)
v.AddArg(x)
return true
}
@@ -5989,8 +5986,8 @@ func rewriteValueARM_OpARMMOVHload(v *Value, config *Config) bool {
return true
}
// match: (MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
// result: x
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVHreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -6003,11 +6000,10 @@ func rewriteValueARM_OpARMMOVHload(v *Value, config *Config) bool {
sym2 := v_1.Aux
ptr2 := v_1.Args[0]
x := v_1.Args[1]
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpARMMOVHreg)
v.AddArg(x)
return true
}

View File

@@ -3332,8 +3332,8 @@ func rewriteValueMIPS_OpMIPSMOVBUload(v *Value, config *Config) bool {
return true
}
// match: (MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
// result: x
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVBUreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -3346,11 +3346,10 @@ func rewriteValueMIPS_OpMIPSMOVBUload(v *Value, config *Config) bool {
sym2 := v_1.Aux
ptr2 := v_1.Args[0]
x := v_1.Args[1]
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpMIPSMOVBUreg)
v.AddArg(x)
return true
}
@@ -3490,8 +3489,8 @@ func rewriteValueMIPS_OpMIPSMOVBload(v *Value, config *Config) bool {
return true
}
// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
// result: x
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVBreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -3504,11 +3503,10 @@ func rewriteValueMIPS_OpMIPSMOVBload(v *Value, config *Config) bool {
sym2 := v_1.Aux
ptr2 := v_1.Args[0]
x := v_1.Args[1]
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpMIPSMOVBreg)
v.AddArg(x)
return true
}
@@ -4148,8 +4146,8 @@ func rewriteValueMIPS_OpMIPSMOVHUload(v *Value, config *Config) bool {
return true
}
// match: (MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
// result: x
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVHUreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -4162,11 +4160,10 @@ func rewriteValueMIPS_OpMIPSMOVHUload(v *Value, config *Config) bool {
sym2 := v_1.Aux
ptr2 := v_1.Args[0]
x := v_1.Args[1]
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpMIPSMOVHUreg)
v.AddArg(x)
return true
}
@@ -4330,8 +4327,8 @@ func rewriteValueMIPS_OpMIPSMOVHload(v *Value, config *Config) bool {
return true
}
// match: (MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
// result: x
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVHreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -4344,11 +4341,10 @@ func rewriteValueMIPS_OpMIPSMOVHload(v *Value, config *Config) bool {
sym2 := v_1.Aux
ptr2 := v_1.Args[0]
x := v_1.Args[1]
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpMIPSMOVHreg)
v.AddArg(x)
return true
}

View File

@@ -7851,7 +7851,7 @@ func rewriteValueS390X_OpS390XMOVBZload(v *Value, config *Config) bool {
_ = b
// match: (MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVDreg x)
// result: (MOVBZreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -7867,7 +7867,7 @@ func rewriteValueS390X_OpS390XMOVBZload(v *Value, config *Config) bool {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpS390XMOVDreg)
v.reset(OpS390XMOVBZreg)
v.AddArg(x)
return true
}
@@ -11021,7 +11021,7 @@ func rewriteValueS390X_OpS390XMOVHZload(v *Value, config *Config) bool {
_ = b
// match: (MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVDreg x)
// result: (MOVHZreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -11037,7 +11037,7 @@ func rewriteValueS390X_OpS390XMOVHZload(v *Value, config *Config) bool {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpS390XMOVDreg)
v.reset(OpS390XMOVHZreg)
v.AddArg(x)
return true
}
@@ -12406,7 +12406,7 @@ func rewriteValueS390X_OpS390XMOVWZload(v *Value, config *Config) bool {
_ = b
// match: (MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVDreg x)
// result: (MOVWZreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -12422,7 +12422,7 @@ func rewriteValueS390X_OpS390XMOVWZload(v *Value, config *Config) bool {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpS390XMOVDreg)
v.reset(OpS390XMOVWZreg)
v.AddArg(x)
return true
}

View File

@@ -74,7 +74,6 @@ type (
// Name Type
TypeDecl struct {
Name *Name
Alias bool
Type Expr
Group *Group // nil means not part of a group
Pragma Pragma

View File

@@ -325,7 +325,7 @@ func (p *parser) constDecl(group *Group) Decl {
return d
}
// TypeSpec = identifier [ "=" ] Type .
// TypeSpec = identifier Type .
func (p *parser) typeDecl(group *Group) Decl {
if trace {
defer p.trace("typeDecl")()
@@ -335,7 +335,6 @@ func (p *parser) typeDecl(group *Group) Decl {
d.init(p)
d.Name = p.name()
d.Alias = p.got(_Assign)
d.Type = p.tryType()
if d.Type == nil {
p.syntax_error("in type declaration")

View File

@@ -619,11 +619,7 @@ func (p *printer) printRawNode(n Node) {
if n.Group == nil {
p.print(_Type, blank)
}
p.print(n.Name, blank)
if n.Alias {
p.print(_Assign, blank)
}
p.print(n.Type)
p.print(n.Name, blank, n.Type)
case *VarDecl:
if n.Group == nil {

View File

@@ -22,20 +22,3 @@ func TestPrint(t *testing.T) {
Fprint(os.Stdout, ast, true)
fmt.Println()
}
func TestPrintString(t *testing.T) {
for _, want := range []string{
"package p",
"package p; type _ = int; type T1 = struct{}; type ( _ = *struct{}; T2 = float32 )",
// TODO(gri) expand
} {
ast, err := ParseBytes([]byte(want), nil, nil, 0)
if err != nil {
t.Error(err)
continue
}
if got := String(ast); got != want {
t.Errorf("%q: got %q", want, got)
}
}
}

View File

@@ -701,7 +701,7 @@ func install(dir string) {
} else {
archive = b
}
compile := []string{pathf("%s/compile", tooldir), "-pack", "-o", b, "-p", pkg}
compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkg}
if gogcflags != "" {
compile = append(compile, strings.Fields(gogcflags)...)
}

View File

@@ -600,7 +600,6 @@ func (t *tester) registerTests() {
})
}
}
return // skip API check on go1.8.typealias branch
if t.goos != "nacl" && t.goos != "android" && !t.iOS() {
t.tests = append(t.tests, distTest{
name: "api",

View File

@@ -71,7 +71,6 @@ var tests = []test{
`const MultiLineConst = ...`, // Multi line constant.
`var MultiLineVar = map\[struct{ ... }\]struct{ ... }{ ... }`, // Multi line variable.
`func MultiLineFunc\(x interface{ ... }\) \(r struct{ ... }\)`, // Multi line function.
`type T1 = T2`, // Type alias
},
[]string{
`const internalConstant = 2`, // No internal constants.
@@ -90,7 +89,6 @@ var tests = []test{
`unexportedTypedConstant`, // No unexported typed constant.
`Field`, // No fields.
`Method`, // No methods.
`type T1 T2`, // Type alias does not display as type declaration.
},
},
// Package dump -u
@@ -267,18 +265,6 @@ var tests = []test{
`error`, // No embedded error.
},
},
// Type T1 dump (alias).
{
"type T1",
[]string{p+".T1"},
[]string{
`type T1 = T2`,
},
[]string{
`type T1 T2`,
`type ExportedType`,
},
},
// Type -u with unexported fields.
{
"type with unexported fields and -u",

View File

@@ -258,11 +258,7 @@ func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
return fmt.Sprintf("func %s%s%s", recv, name, fnc)
case *ast.TypeSpec:
sep := " "
if n.Assign.IsValid() {
sep = " = "
}
return fmt.Sprintf("type %s%s%s", n.Name.Name, sep, pkg.oneLineNodeDepth(n.Type, depth))
return fmt.Sprintf("type %s %s", n.Name.Name, pkg.oneLineNodeDepth(n.Type, depth))
case *ast.FuncType:
var params []string

View File

@@ -172,7 +172,3 @@ const (
)
const ConstGroup4 ExportedType = ExportedType{}
type T2 int
type T1 = T2

View File

@@ -1103,17 +1103,26 @@
// CGO_CFLAGS
// Flags that cgo will pass to the compiler when compiling
// C code.
// CGO_CPPFLAGS
// Flags that cgo will pass to the compiler when compiling
// C or C++ code.
// CGO_CXXFLAGS
// Flags that cgo will pass to the compiler when compiling
// C++ code.
// CGO_FFLAGS
// Flags that cgo will pass to the compiler when compiling
// Fortran code.
// CGO_LDFLAGS
// Flags that cgo will pass to the compiler when linking.
// CGO_CFLAGS_ALLOW
// A regular expression specifying additional flags to allow
// to appear in #cgo CFLAGS source code directives.
// Does not apply to the CGO_CFLAGS environment variable.
// CGO_CFLAGS_DISALLOW
// A regular expression specifying flags that must be disallowed
// from appearing in #cgo CFLAGS source code directives.
// Does not apply to the CGO_CFLAGS environment variable.
// CGO_CPPFLAGS, CGO_CPPFLAGS_ALLOW, CGO_CPPFLAGS_DISALLOW
// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
// but for the C preprocessor.
// CGO_CXXFLAGS, CGO_CXXFLAGS_ALLOW, CGO_CXXFLAGS_DISALLOW
// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
// but for the C++ compiler.
// CGO_FFLAGS, CGO_FFLAGS_ALLOW, CGO_FFLAGS_DISALLOW
// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
// but for the Fortran compiler.
// CGO_LDFLAGS, CGO_LDFLAGS_ALLOW, CGO_LDFLAGS_DISALLOW
// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
// but for the linker.
// CXX
// The command to use to compile C++ code.
// PKG_CONFIG

View File

@@ -1670,26 +1670,35 @@ func splitPkgConfigOutput(out []byte) []string {
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) {
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
for _, pkg := range pkgs {
if !SafeArg(pkg) {
return nil, nil, fmt.Errorf("invalid pkg-config package name: %s", pkg)
}
}
var out []byte
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--cflags", pkgs)
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--cflags", "--", pkgs)
if err != nil {
b.showOutput(p.Dir, b.pkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
err = errPrintedOutput
return
return nil, nil, errPrintedOutput
}
if len(out) > 0 {
cflags = splitPkgConfigOutput(out)
if err := checkCompilerFlags("CFLAGS", "pkg-config --cflags", cflags); err != nil {
return nil, nil, err
}
}
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--libs", pkgs)
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--libs", "--", pkgs)
if err != nil {
b.showOutput(p.Dir, b.pkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
err = errPrintedOutput
return
return nil, nil, errPrintedOutput
}
if len(out) > 0 {
ldflags = strings.Fields(string(out))
if err := checkLinkerFlags("CFLAGS", "pkg-config --cflags", ldflags); err != nil {
return nil, nil, err
}
}
}
return
@@ -2117,6 +2126,17 @@ func (b *builder) processOutput(out []byte) string {
// It returns the command output and any errors that occurred.
func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) {
cmdline := stringList(cmdargs...)
for _, arg := range cmdline {
// GNU binutils commands, including gcc and gccgo, interpret an argument
// @foo anywhere in the command line (even following --) as meaning
// "read and insert arguments from the file named foo."
// Don't say anything that might be misinterpreted that way.
if strings.HasPrefix(arg, "@") {
return nil, fmt.Errorf("invalid command-line argument %s in command: %s", arg, joinUnambiguously(cmdline))
}
}
if buildN || buildX {
var envcmdline string
for i := range env {
@@ -2357,6 +2377,9 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
// additional reflect type data.
gcargs = append(gcargs, "-+")
}
if p.Standard {
gcargs = append(gcargs, "-std")
}
// If we're giving the compiler the entire package (no C etc files), tell it that,
// so that it can give good error messages about forward declarations.
@@ -3255,23 +3278,45 @@ func envList(key, def string) []string {
return strings.Fields(v)
}
// Return the flags to use when invoking the C, C++ or Fortran compilers, or cgo.
func (b *builder) cflags(p *Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) {
// CFlags returns the flags to use when invoking the C, C++ or Fortran compilers, or cgo.
func (b *builder) cflags(p *Package) (cppflags, cflags, cxxflags, fflags, ldflags []string, err error) {
defaults := "-g -O2"
cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
fflags = stringList(envList("CGO_FFLAGS", defaults), p.CgoFFLAGS)
ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
if cppflags, err = buildFlags("CPPFLAGS", "", p.CgoCPPFLAGS, checkCompilerFlags); err != nil {
return
}
if cflags, err = buildFlags("CFLAGS", defaults, p.CgoCFLAGS, checkCompilerFlags); err != nil {
return
}
if cxxflags, err = buildFlags("CXXFLAGS", defaults, p.CgoCXXFLAGS, checkCompilerFlags); err != nil {
return
}
if fflags, err = buildFlags("FFLAGS", defaults, p.CgoFFLAGS, checkCompilerFlags); err != nil {
return
}
if ldflags, err = buildFlags("LDFLAGS", defaults, p.CgoLDFLAGS, checkLinkerFlags); err != nil {
return
}
return
}
func buildFlags(name, defaults string, fromPackage []string, check func(string, string, []string) error) ([]string, error) {
if err := check(name, "#cgo "+name, fromPackage); err != nil {
return nil, err
}
return stringList(envList("CGO_"+name, defaults), fromPackage), nil
}
var cgoRe = regexp.MustCompile(`[/\\:]`)
func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) {
p := a.p
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.cflags(p)
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS, err := b.cflags(p)
if err != nil {
return nil, nil, err
}
cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
// If we are compiling Objective-C code, then we need to link against libobjc
@@ -3335,6 +3380,12 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil
}
// Update $CGO_LDFLAGS with p.CgoLDFLAGS.
// These flags are recorded in the generated _cgo_gotypes.go file
// using //go:cgo_ldflag directives, the compiler records them in the
// object file for the package, and then the Go linker passes them
// along to the host linker. At this point in the code, cgoLDFLAGS
// consists of the original $CGO_LDFLAGS (unchecked) and all the
// flags put together from source code (checked).
var cgoenv []string
if len(cgoLDFLAGS) > 0 {
flags := make([]string, len(cgoLDFLAGS))
@@ -3684,7 +3735,11 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
// Run SWIG on one SWIG input file.
func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) {
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p)
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _, err := b.cflags(p)
if err != nil {
return "", "", err
}
var cflags []string
if cxx {
cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)

View File

@@ -90,7 +90,12 @@ func findEnv(env []envVar, name string) string {
func extraEnvVars() []envVar {
var b builder
b.init()
cppflags, cflags, cxxflags, fflags, ldflags := b.cflags(&Package{})
cppflags, cflags, cxxflags, fflags, ldflags, err := b.cflags(&Package{})
if err != nil {
// Should not happen - b.CFlags was given an empty package.
fmt.Fprintf(os.Stderr, "go: invalid cflags: %v\n", err)
return nil
}
return []envVar{
{"PKG_CONFIG", b.pkgconfigCmd()},
{"CGO_CFLAGS", strings.Join(cflags, " ")},

View File

@@ -439,6 +439,11 @@ func downloadPackage(p *Package) error {
p.build.PkgRoot = filepath.Join(list[0], "pkg")
}
root := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
if err := checkNestedVCS(vcs, root, p.build.SrcRoot); err != nil {
return err
}
// If we've considered this repository already, don't do it again.
if downloadRootCache[root] {
return nil

View File

@@ -1120,7 +1120,7 @@ func testMove(t *testing.T, vcs, url, base, config string) {
tg.runFail("get", "-d", "-u", url)
tg.grepStderr("is a custom import path for", "go get -d -u "+url+" failed for wrong reason")
tg.runFail("get", "-d", "-f", "-u", url)
tg.grepStderr("validating server certificate|not found", "go get -d -f -u "+url+" failed for wrong reason")
tg.grepStderr("validating server certificate|[nN]ot [fF]ound", "go get -d -f -u "+url+" failed for wrong reason")
}
func TestInternalPackageErrorsAreHandled(t *testing.T) {
@@ -1141,10 +1141,9 @@ func TestMoveGit(t *testing.T) {
testMove(t, "git", "rsc.io/pdf", "pdf", "rsc.io/pdf/.git/config")
}
// TODO(rsc): Set up a test case on bitbucket for hg.
// func TestMoveHG(t *testing.T) {
// testMove(t, "hg", "rsc.io/x86/x86asm", "x86", "rsc.io/x86/.hg/hgrc")
// }
func TestMoveHG(t *testing.T) {
testMove(t, "hg", "vcs-test.golang.org/go/custom-hg-hello", "custom-hg-hello", "vcs-test.golang.org/go/custom-hg-hello/.hg/hgrc")
}
// TODO(rsc): Set up a test case on SourceForge (?) for svn.
// func testMoveSVN(t *testing.T) {
@@ -1273,6 +1272,25 @@ func TestGetGitDefaultBranch(t *testing.T) {
tg.grepStdout(`\* another-branch`, "not on correct default branch")
}
func TestAccidentalGitCheckout(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
if _, err := exec.LookPath("git"); err != nil {
t.Skip("skipping because git binary not found")
}
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.tempDir("src")
tg.setenv("GOPATH", tg.path("."))
tg.runFail("get", "-u", "vcs-test.golang.org/go/test1-svn-git")
tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
tg.runFail("get", "-u", "vcs-test.golang.org/go/test2-svn-git/test2main")
tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
}
func TestErrorMessageForSyntaxErrorInTestGoFileSaysFAIL(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@@ -2336,7 +2354,7 @@ func TestCgoHandlesWlORIGIN(t *testing.T) {
defer tg.cleanup()
tg.parallel()
tg.tempFile("src/origin/origin.go", `package origin
// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
// #cgo !darwin LDFLAGS: -Wl,-rpath,$ORIGIN
// void f(void) {}
import "C"
func f() { C.f() }`)
@@ -2719,7 +2737,7 @@ func TestImportMain(t *testing.T) {
func TestFoo(t *testing.T) {}
`)
tg.setenv("GOPATH", tg.path("."))
tg.creatingTemp("x")
tg.creatingTemp("x" + exeSuffix)
tg.run("build", "x")
tg.run("test", "x")
@@ -3773,3 +3791,150 @@ func TestA(t *testing.T) {}`)
tg.grepStdout("pkgs$", "expected package not listed")
tg.grepStdout("pkgs/a", "expected package not listed")
}
func TestBadCommandLines(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("src/x/x.go", "package x\n")
tg.setenv("GOPATH", tg.path("."))
tg.run("build", "x")
tg.tempFile("src/x/@y.go", "package x\n")
tg.runFail("build", "x")
tg.grepStderr("invalid input file name \"@y.go\"", "did not reject @y.go")
tg.must(os.Remove(tg.path("src/x/@y.go")))
tg.tempFile("src/x/-y.go", "package x\n")
tg.runFail("build", "x")
tg.grepStderr("invalid input file name \"-y.go\"", "did not reject -y.go")
tg.must(os.Remove(tg.path("src/x/-y.go")))
tg.runFail("build", "-gcflags=@x", "x")
tg.grepStderr("invalid command-line argument @x in command", "did not reject @x during exec")
tg.tempFile("src/@x/x.go", "package x\n")
tg.setenv("GOPATH", tg.path("."))
tg.runFail("build", "@x")
tg.grepStderr("invalid input directory name \"@x\"", "did not reject @x directory")
tg.tempFile("src/@x/y/y.go", "package y\n")
tg.setenv("GOPATH", tg.path("."))
tg.runFail("build", "@x/y")
tg.grepStderr("invalid import path \"@x/y\"", "did not reject @x/y import path")
tg.tempFile("src/-x/x.go", "package x\n")
tg.setenv("GOPATH", tg.path("."))
tg.runFail("build", "--", "-x")
tg.grepStderr("invalid input directory name \"-x\"", "did not reject -x directory")
tg.tempFile("src/-x/y/y.go", "package y\n")
tg.setenv("GOPATH", tg.path("."))
tg.runFail("build", "--", "-x/y")
tg.grepStderr("invalid import path \"-x/y\"", "did not reject -x/y import path")
}
func TestBadCgoDirectives(t *testing.T) {
if !canCgo {
t.Skip("no cgo")
}
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("src/x/x.go", "package x\n")
tg.setenv("GOPATH", tg.path("."))
tg.tempFile("src/x/x.go", `package x
//go:cgo_ldflag "-fplugin=foo.so"
`)
tg.runFail("build", "x")
tg.grepStderr("//go:cgo_ldflag .* only allowed in cgo-generated code", "did not reject //go:cgo_ldflag directive")
tg.must(os.Remove(tg.path("src/x/x.go")))
tg.runFail("build", "x")
tg.grepStderr("no buildable Go source files", "did not report missing source code")
tg.tempFile("src/x/_cgo_yy.go", `package x
//go:cgo_ldflag "-fplugin=foo.so"
`)
tg.runFail("build", "x")
tg.grepStderr("no buildable Go source files", "did not report missing source code") // _* files are ignored...
tg.runFail("build", tg.path("src/x/_cgo_yy.go")) // ... but if forced, the comment is rejected
// Actually, today there is a separate issue that _ files named
// on the command-line are ignored. Once that is fixed,
// we want to see the cgo_ldflag error.
tg.grepStderr("//go:cgo_ldflag only allowed in cgo-generated code|no buildable Go source files", "did not reject //go:cgo_ldflag directive")
tg.must(os.Remove(tg.path("src/x/_cgo_yy.go")))
tg.tempFile("src/x/x.go", "package x\n")
tg.tempFile("src/x/y.go", `package x
// #cgo CFLAGS: -fplugin=foo.so
import "C"
`)
tg.runFail("build", "x")
tg.grepStderr("invalid flag in #cgo CFLAGS: -fplugin=foo.so", "did not reject -fplugin")
tg.tempFile("src/x/y.go", `package x
// #cgo CFLAGS: -Ibar -fplugin=foo.so
import "C"
`)
tg.runFail("build", "x")
tg.grepStderr("invalid flag in #cgo CFLAGS: -fplugin=foo.so", "did not reject -fplugin")
tg.tempFile("src/x/y.go", `package x
// #cgo pkg-config: -foo
import "C"
`)
tg.runFail("build", "x")
tg.grepStderr("invalid pkg-config package name: -foo", "did not reject pkg-config: -foo")
tg.tempFile("src/x/y.go", `package x
// #cgo pkg-config: @foo
import "C"
`)
tg.runFail("build", "x")
tg.grepStderr("invalid pkg-config package name: @foo", "did not reject pkg-config: -foo")
tg.tempFile("src/x/y.go", `package x
// #cgo CFLAGS: @foo
import "C"
`)
tg.runFail("build", "x")
tg.grepStderr("invalid flag in #cgo CFLAGS: @foo", "did not reject @foo flag")
tg.tempFile("src/x/y.go", `package x
// #cgo CFLAGS: -D
import "C"
`)
tg.runFail("build", "x")
tg.grepStderr("invalid flag in #cgo CFLAGS: -D without argument", "did not reject trailing -I flag")
// Note that -I @foo is allowed because we rewrite it into -I /path/to/src/@foo
// before the check is applied. There's no such rewrite for -D.
tg.tempFile("src/x/y.go", `package x
// #cgo CFLAGS: -D @foo
import "C"
`)
tg.runFail("build", "x")
tg.grepStderr("invalid flag in #cgo CFLAGS: -D @foo", "did not reject -D @foo flag")
tg.tempFile("src/x/y.go", `package x
// #cgo CFLAGS: -D@foo
import "C"
`)
tg.runFail("build", "x")
tg.grepStderr("invalid flag in #cgo CFLAGS: -D@foo", "did not reject -D@foo flag")
tg.setenv("CGO_CFLAGS", "-D@foo")
tg.tempFile("src/x/y.go", `package x
import "C"
`)
tg.run("build", "-n", "x")
tg.grepStderr("-D@foo", "did not find -D@foo in commands")
}

View File

@@ -468,17 +468,26 @@ Environment variables for use with cgo:
CGO_CFLAGS
Flags that cgo will pass to the compiler when compiling
C code.
CGO_CPPFLAGS
Flags that cgo will pass to the compiler when compiling
C or C++ code.
CGO_CXXFLAGS
Flags that cgo will pass to the compiler when compiling
C++ code.
CGO_FFLAGS
Flags that cgo will pass to the compiler when compiling
Fortran code.
CGO_LDFLAGS
Flags that cgo will pass to the compiler when linking.
CGO_CFLAGS_ALLOW
A regular expression specifying additional flags to allow
to appear in #cgo CFLAGS source code directives.
Does not apply to the CGO_CFLAGS environment variable.
CGO_CFLAGS_DISALLOW
A regular expression specifying flags that must be disallowed
from appearing in #cgo CFLAGS source code directives.
Does not apply to the CGO_CFLAGS environment variable.
CGO_CPPFLAGS, CGO_CPPFLAGS_ALLOW, CGO_CPPFLAGS_DISALLOW
Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
but for the C preprocessor.
CGO_CXXFLAGS, CGO_CXXFLAGS_ALLOW, CGO_CXXFLAGS_DISALLOW
Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
but for the C++ compiler.
CGO_FFLAGS, CGO_FFLAGS_ALLOW, CGO_FFLAGS_DISALLOW
Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
but for the Fortran compiler.
CGO_LDFLAGS, CGO_LDFLAGS_ALLOW, CGO_LDFLAGS_DISALLOW
Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
but for the linker.
CXX
The command to use to compile C++ code.
PKG_CONFIG

View File

@@ -22,6 +22,7 @@ import (
"strconv"
"strings"
"unicode"
"unicode/utf8"
)
var ignoreImports bool // control whether we ignore imports in packages
@@ -47,6 +48,8 @@ type Package struct {
BinaryOnly bool `json:",omitempty"` // package cannot be recompiled
// Source files
// If you add to this list you MUST add to p.AllFiles (below) too.
// Otherwise file name security lists will not apply to any new additions.
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints
@@ -78,6 +81,8 @@ type Package struct {
DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
// Test information
// If you add to this list you MUST add to p.AllFiles (below) too.
// Otherwise file name security lists will not apply to any new additions.
TestGoFiles []string `json:",omitempty"` // _test.go files in package
TestImports []string `json:",omitempty"` // imports from TestGoFiles
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
@@ -106,6 +111,30 @@ type Package struct {
gobinSubdir bool // install target would be subdir of GOBIN
}
// allFiles returns the names of all the files considered for the package.
// This is used for sanity and security checks, so we include all files,
// even IgnoredGoFiles, because some subcommands consider them.
// The go/build package filtered others out (like foo_wrongGOARCH.s)
// and that's OK.
func (p *Package) allFiles() []string {
return stringList(
p.GoFiles,
p.CgoFiles,
p.IgnoredGoFiles,
p.CFiles,
p.CXXFiles,
p.MFiles,
p.HFiles,
p.FFiles,
p.SFiles,
p.SwigFiles,
p.SwigCXXFiles,
p.SysoFiles,
p.TestGoFiles,
p.XTestGoFiles,
)
}
// vendored returns the vendor-resolved version of imports,
// which should be p.TestImports or p.XTestImports, NOT p.Imports.
// The imports in p.TestImports and p.XTestImports are not recursively
@@ -990,22 +1019,8 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// To avoid problems on case-insensitive files, we reject any package
// where two different input files have equal names under a case-insensitive
// comparison.
f1, f2 := foldDup(stringList(
p.GoFiles,
p.CgoFiles,
p.IgnoredGoFiles,
p.CFiles,
p.CXXFiles,
p.MFiles,
p.HFiles,
p.FFiles,
p.SFiles,
p.SysoFiles,
p.SwigFiles,
p.SwigCXXFiles,
p.TestGoFiles,
p.XTestGoFiles,
))
inputs := p.allFiles()
f1, f2 := foldDup(inputs)
if f1 != "" {
p.Error = &PackageError{
ImportStack: stk.copy(),
@@ -1014,6 +1029,37 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
return p
}
// If first letter of input file is ASCII, it must be alphanumeric.
// This avoids files turning into flags when invoking commands,
// and other problems we haven't thought of yet.
// Also, _cgo_ files must be generated by us, not supplied.
// They are allowed to have //go:cgo_ldflag directives.
// The directory scan ignores files beginning with _,
// so we shouldn't see any _cgo_ files anyway, but just be safe.
for _, file := range inputs {
if !SafeArg(file) || strings.HasPrefix(file, "_cgo_") {
p.Error = &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("invalid input file name %q", file),
}
return p
}
}
if name := pathpkg.Base(p.ImportPath); !SafeArg(name) {
p.Error = &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("invalid input directory name %q", name),
}
return p
}
if !SafeArg(p.ImportPath) {
p.Error = &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("invalid import path %q", p.ImportPath),
}
return p
}
// Build list of imported packages and full dependency list.
imports := make([]*Package, 0, len(p.Imports))
deps := make(map[string]*Package)
@@ -1130,6 +1176,22 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
return p
}
// SafeArg reports whether arg is a "safe" command-line argument,
// meaning that when it appears in a command-line, it probably
// doesn't have some special meaning other than its own name.
// Obviously args beginning with - are not safe (they look like flags).
// Less obviously, args beginning with @ are not safe (they look like
// GNU binutils flagfile specifiers, sometimes called "response files").
// To be conservative, we reject almost any arg beginning with non-alphanumeric ASCII.
// We accept leading . _ and / as likely in file system paths.
func SafeArg(name string) bool {
if name == "" {
return false
}
c := name[0]
return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf
}
// usesSwig reports whether the package needs to run SWIG.
func (p *Package) usesSwig() bool {
return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0

159
src/cmd/go/security.go Normal file
View File

@@ -0,0 +1,159 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Checking of compiler and linker flags.
// We must avoid flags like -fplugin=, which can allow
// arbitrary code execution during the build.
// Do not make changes here without carefully
// considering the implications.
// (That's why the code is isolated in a file named security.go.)
//
// Note that -Wl,foo means split foo on commas and pass to
// the linker, so that -Wl,-foo,bar means pass -foo bar to
// the linker. Similarly -Wa,foo for the assembler and so on.
// If any of these are permitted, the wildcard portion must
// disallow commas.
//
// Note also that GNU binutils accept any argument @foo
// as meaning "read more flags from the file foo", so we must
// guard against any command-line argument beginning with @,
// even things like "-I @foo".
// We use load.SafeArg (which is even more conservative)
// to reject these.
//
// Even worse, gcc -I@foo (one arg) turns into cc1 -I @foo (two args),
// so although gcc doesn't expand the @foo, cc1 will.
// So out of paranoia, we reject @ at the beginning of every
// flag argument that might be split into its own argument.
package main
import (
"fmt"
"os"
"regexp"
)
var re = regexp.MustCompile
var validCompilerFlags = []*regexp.Regexp{
re(`-D([A-Za-z_].*)`),
re(`-I([^@\-].*)`),
re(`-O`),
re(`-O([^@\-].*)`),
re(`-W`),
re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
re(`-f(no-)?objc-arc`),
re(`-f(no-)?omit-frame-pointer`),
re(`-f(no-)?(pic|PIC|pie|PIE)`),
re(`-f(no-)?split-stack`),
re(`-f(no-)?stack-(.+)`),
re(`-f(no-)?strict-aliasing`),
re(`-fsanitize=(.+)`),
re(`-g([^@\-].*)?`),
re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
re(`-m(no-)?stack-(.+)`),
re(`-mmacosx-(.+)`),
re(`-mnop-fun-dllimport`),
re(`-pthread`),
re(`-std=([^@\-].*)`),
re(`-x([^@\-].*)`),
}
var validCompilerFlagsWithNextArg = []string{
"-D",
"-I",
"-framework",
"-x",
}
var validLinkerFlags = []*regexp.Regexp{
re(`-F([^@\-].*)`),
re(`-l([^@\-].*)`),
re(`-L([^@\-].*)`),
re(`-f(no-)?(pic|PIC|pie|PIE)`),
re(`-fsanitize=([^@\-].*)`),
re(`-g([^@\-].*)?`),
re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
re(`-(pic|PIC|pie|PIE)`),
re(`-pthread`),
// Note that any wildcards in -Wl need to exclude comma,
// since -Wl splits its argument at commas and passes
// them all to the linker uninterpreted. Allowing comma
// in a wildcard would allow tunnelling arbitrary additional
// linker arguments through one of these.
re(`-Wl,-rpath,([^,@\-][^,]+)`),
re(`-Wl,--(no-)?warn-([^,]+)`),
re(`[a-zA-Z0-9_].*\.(o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
}
var validLinkerFlagsWithNextArg = []string{
"-F",
"-l",
"-L",
"-framework",
}
func checkCompilerFlags(name, source string, list []string) error {
return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg)
}
func checkLinkerFlags(name, source string, list []string) error {
return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg)
}
func checkFlags(name, source string, list []string, valid []*regexp.Regexp, validNext []string) error {
// Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc.
var (
allow *regexp.Regexp
disallow *regexp.Regexp
)
if env := os.Getenv("CGO_" + name + "_ALLOW"); env != "" {
r, err := regexp.Compile(env)
if err != nil {
return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err)
}
allow = r
}
if env := os.Getenv("CGO_" + name + "_DISALLOW"); env != "" {
r, err := regexp.Compile(env)
if err != nil {
return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err)
}
disallow = r
}
Args:
for i := 0; i < len(list); i++ {
arg := list[i]
if disallow != nil && disallow.FindString(arg) == arg {
goto Bad
}
if allow != nil && allow.FindString(arg) == arg {
continue Args
}
for _, re := range valid {
if re.FindString(arg) == arg { // must be complete match
continue Args
}
}
for _, x := range validNext {
if arg == x {
if i+1 < len(list) && SafeArg(list[i+1]) {
i++
continue Args
}
if i+1 < len(list) {
return fmt.Errorf("invalid flag in %s: %s %s", source, arg, list[i+1])
}
return fmt.Errorf("invalid flag in %s: %s without argument", source, arg)
}
}
Bad:
return fmt.Errorf("invalid flag in %s: %s", source, arg)
}
return nil
}

240
src/cmd/go/security_test.go Normal file
View File

@@ -0,0 +1,240 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"os"
"testing"
)
var goodCompilerFlags = [][]string{
{"-DFOO"},
{"-Dfoo=bar"},
{"-I/"},
{"-I/etc/passwd"},
{"-I."},
{"-O"},
{"-O2"},
{"-Osmall"},
{"-W"},
{"-Wall"},
{"-fobjc-arc"},
{"-fno-objc-arc"},
{"-fomit-frame-pointer"},
{"-fno-omit-frame-pointer"},
{"-fpic"},
{"-fno-pic"},
{"-fPIC"},
{"-fno-PIC"},
{"-fpie"},
{"-fno-pie"},
{"-fPIE"},
{"-fno-PIE"},
{"-fsplit-stack"},
{"-fno-split-stack"},
{"-fstack-xxx"},
{"-fno-stack-xxx"},
{"-fsanitize=hands"},
{"-g"},
{"-ggdb"},
{"-march=souza"},
{"-mcpu=123"},
{"-mfpu=123"},
{"-mtune=happybirthday"},
{"-mstack-overflow"},
{"-mno-stack-overflow"},
{"-mmacosx-version"},
{"-mnop-fun-dllimport"},
{"-pthread"},
{"-std=c99"},
{"-xc"},
{"-D", "FOO"},
{"-D", "foo=bar"},
{"-I", "."},
{"-I", "/etc/passwd"},
{"-I", "世界"},
{"-framework", "Chocolate"},
{"-x", "c"},
}
var badCompilerFlags = [][]string{
{"-D@X"},
{"-D-X"},
{"-I@dir"},
{"-I-dir"},
{"-O@1"},
{"-Wa,-foo"},
{"-W@foo"},
{"-g@gdb"},
{"-g-gdb"},
{"-march=@dawn"},
{"-march=-dawn"},
{"-std=@c99"},
{"-std=-c99"},
{"-x@c"},
{"-x-c"},
{"-D", "@foo"},
{"-D", "-foo"},
{"-I", "@foo"},
{"-I", "-foo"},
{"-framework", "-Caffeine"},
{"-framework", "@Home"},
{"-x", "--c"},
{"-x", "@obj"},
}
func TestCheckCompilerFlags(t *testing.T) {
for _, f := range goodCompilerFlags {
if err := checkCompilerFlags("test", "test", f); err != nil {
t.Errorf("unexpected error for %q: %v", f, err)
}
}
for _, f := range badCompilerFlags {
if err := checkCompilerFlags("test", "test", f); err == nil {
t.Errorf("missing error for %q", f)
}
}
}
var goodLinkerFlags = [][]string{
{"-Fbar"},
{"-lbar"},
{"-Lbar"},
{"-fpic"},
{"-fno-pic"},
{"-fPIC"},
{"-fno-PIC"},
{"-fpie"},
{"-fno-pie"},
{"-fPIE"},
{"-fno-PIE"},
{"-fsanitize=hands"},
{"-g"},
{"-ggdb"},
{"-march=souza"},
{"-mcpu=123"},
{"-mfpu=123"},
{"-mtune=happybirthday"},
{"-pic"},
{"-pthread"},
{"-Wl,-rpath,foo"},
{"-Wl,-rpath,$ORIGIN/foo"},
{"-Wl,--warn-error"},
{"-Wl,--no-warn-error"},
{"foo.so"},
{"_世界.dll"},
{"libcgosotest.dylib"},
{"-F", "framework"},
{"-l", "."},
{"-l", "/etc/passwd"},
{"-l", "世界"},
{"-L", "framework"},
{"-framework", "Chocolate"},
}
var badLinkerFlags = [][]string{
{"-DFOO"},
{"-Dfoo=bar"},
{"-O"},
{"-O2"},
{"-Osmall"},
{"-W"},
{"-Wall"},
{"-fobjc-arc"},
{"-fno-objc-arc"},
{"-fomit-frame-pointer"},
{"-fno-omit-frame-pointer"},
{"-fsplit-stack"},
{"-fno-split-stack"},
{"-fstack-xxx"},
{"-fno-stack-xxx"},
{"-mstack-overflow"},
{"-mno-stack-overflow"},
{"-mmacosx-version"},
{"-mnop-fun-dllimport"},
{"-std=c99"},
{"-xc"},
{"-D", "FOO"},
{"-D", "foo=bar"},
{"-I", "FOO"},
{"-L", "@foo"},
{"-L", "-foo"},
{"-x", "c"},
{"-D@X"},
{"-D-X"},
{"-I@dir"},
{"-I-dir"},
{"-O@1"},
{"-Wa,-foo"},
{"-W@foo"},
{"-g@gdb"},
{"-g-gdb"},
{"-march=@dawn"},
{"-march=-dawn"},
{"-std=@c99"},
{"-std=-c99"},
{"-x@c"},
{"-x-c"},
{"-D", "@foo"},
{"-D", "-foo"},
{"-I", "@foo"},
{"-I", "-foo"},
{"-l", "@foo"},
{"-l", "-foo"},
{"-framework", "-Caffeine"},
{"-framework", "@Home"},
{"-x", "--c"},
{"-x", "@obj"},
{"-Wl,-rpath,@foo"},
}
func TestCheckLinkerFlags(t *testing.T) {
for _, f := range goodLinkerFlags {
if err := checkLinkerFlags("test", "test", f); err != nil {
t.Errorf("unexpected error for %q: %v", f, err)
}
}
for _, f := range badLinkerFlags {
if err := checkLinkerFlags("test", "test", f); err == nil {
t.Errorf("missing error for %q", f)
}
}
}
func TestCheckFlagAllowDisallow(t *testing.T) {
if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err == nil {
t.Fatalf("missing error for -disallow")
}
os.Setenv("CGO_TEST_ALLOW", "-disallo")
if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err == nil {
t.Fatalf("missing error for -disallow with CGO_TEST_ALLOW=-disallo")
}
os.Setenv("CGO_TEST_ALLOW", "-disallow")
if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err != nil {
t.Fatalf("unexpected error for -disallow with CGO_TEST_ALLOW=-disallow: %v", err)
}
os.Unsetenv("CGO_TEST_ALLOW")
if err := checkCompilerFlags("TEST", "test", []string{"-Wall"}); err != nil {
t.Fatalf("unexpected error for -Wall: %v", err)
}
os.Setenv("CGO_TEST_DISALLOW", "-Wall")
if err := checkCompilerFlags("TEST", "test", []string{"-Wall"}); err == nil {
t.Fatalf("missing error for -Wall with CGO_TEST_DISALLOW=-Wall")
}
os.Setenv("CGO_TEST_ALLOW", "-Wall") // disallow wins
if err := checkCompilerFlags("TEST", "test", []string{"-Wall"}); err == nil {
t.Fatalf("missing error for -Wall with CGO_TEST_DISALLOW=-Wall and CGO_TEST_ALLOW=-Wall")
}
os.Setenv("CGO_TEST_ALLOW", "-fplugin.*")
os.Setenv("CGO_TEST_DISALLOW", "-fplugin=lint.so")
if err := checkCompilerFlags("TEST", "test", []string{"-fplugin=faster.so"}); err != nil {
t.Fatalf("unexpected error for -fplugin=faster.so: %v", err)
}
if err := checkCompilerFlags("TEST", "test", []string{"-fplugin=lint.so"}); err == nil {
t.Fatalf("missing error for -fplugin=lint.so: %v", err)
}
}

View File

@@ -497,11 +497,28 @@ func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {
return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
}
var vcsRet *vcsCmd
var rootRet string
origDir := dir
for len(dir) > len(srcRoot) {
for _, vcs := range vcsList {
if _, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil {
return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil
root := filepath.ToSlash(dir[len(srcRoot)+1:])
// Record first VCS we find, but keep looking,
// to detect mistakes like one kind of VCS inside another.
if vcsRet == nil {
vcsRet = vcs
rootRet = root
continue
}
// Allow .git inside .git, which can arise due to submodules.
if vcsRet == vcs && vcs.cmd == "git" {
continue
}
// Otherwise, we have one VCS inside a different VCS.
return nil, "", fmt.Errorf("directory %q uses %s, but parent %q uses %s",
filepath.Join(srcRoot, rootRet), vcsRet.cmd, filepath.Join(srcRoot, root), vcs.cmd)
}
}
@@ -514,9 +531,48 @@ func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {
dir = ndir
}
if vcsRet != nil {
return vcsRet, rootRet, nil
}
return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)
}
// checkNestedVCS checks for an incorrectly-nested VCS-inside-VCS
// situation for dir, checking parents up until srcRoot.
func checkNestedVCS(vcs *vcsCmd, dir, srcRoot string) error {
if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
return fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
}
otherDir := dir
for len(otherDir) > len(srcRoot) {
for _, otherVCS := range vcsList {
if _, err := os.Stat(filepath.Join(otherDir, "."+otherVCS.cmd)); err == nil {
// Allow expected vcs in original dir.
if otherDir == dir && otherVCS == vcs {
continue
}
// Allow .git inside .git, which can arise due to submodules.
if otherVCS == vcs && vcs.cmd == "git" {
continue
}
// Otherwise, we have one VCS inside a different VCS.
return fmt.Errorf("directory %q uses %s, but parent %q uses %s", dir, vcs.cmd, otherDir, otherVCS.cmd)
}
}
// Move to parent.
newDir := filepath.Dir(otherDir)
if len(newDir) >= len(otherDir) {
// Shouldn't happen, but just in case, stop.
break
}
otherDir = newDir
}
return nil
}
// repoRoot represents a version control system, a repo, and a root of
// where to put it on disk.
type repoRoot struct {

View File

@@ -1,24 +0,0 @@
package q
import "p"
type _ = int
type a = struct{ x int }
type b = p.B
type (
_ = chan<- int
aa = interface{}
bb = p.BB
)
// TODO(gri) We may want to put the '=' into a separate column if
// we have mixed (regular and alias) type declarations in a group.
type (
_ chan<- int
_ = chan<- int
aa0 interface{}
aaa = interface{}
bb0 p.BB
bbb = p.BB
)

View File

@@ -1,24 +0,0 @@
package q
import "p"
type _ = int
type a = struct{ x int }
type b = p.B
type (
_ = chan<- int
aa = interface{}
bb = p.BB
)
// TODO(gri) We may want to put the '=' into a separate column if
// we have mixed (regular and alias) type declarations in a group.
type (
_ chan<- int
_ = chan<- int
aa0 interface{}
aaa = interface{}
bb0 p.BB
bbb = p.BB
)

View File

@@ -322,15 +322,13 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
// Rewrite p, if necessary, to access global data via the global offset table.
func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
var add, lea, mov obj.As
var lea, mov obj.As
var reg int16
if p.Mode == 64 {
add = AADDQ
lea = ALEAQ
mov = AMOVQ
reg = REG_R15
} else {
add = AADDL
lea = ALEAL
mov = AMOVL
reg = REG_CX
@@ -347,8 +345,10 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
// ADUFFxxx $offset
// becomes
// $MOV runtime.duffxxx@GOT, $reg
// $ADD $offset, $reg
// $LEA $offset($reg), $reg
// CALL $reg
// (we use LEAx rather than ADDx because ADDx clobbers
// flags and duffzero on 386 does not otherwise do so)
var sym *obj.LSym
if p.As == obj.ADUFFZERO {
sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
@@ -365,9 +365,10 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
p.To.Offset = 0
p.To.Sym = nil
p1 := obj.Appendp(ctxt, p)
p1.As = add
p1.From.Type = obj.TYPE_CONST
p1.As = lea
p1.From.Type = obj.TYPE_MEM
p1.From.Offset = offset
p1.From.Reg = reg
p1.To.Type = obj.TYPE_REG
p1.To.Reg = reg
p2 := obj.Appendp(ctxt, p1)

View File

@@ -324,18 +324,36 @@ func isRuntimeDepPkg(pkg string) bool {
return strings.HasPrefix(pkg, "runtime/internal/") && !strings.HasSuffix(pkg, "_test")
}
// Estimate the max size needed to hold any new trampolines created for this function. This
// is used to determine when the section can be split if it becomes too large, to ensure that
// the trampolines are in the same section as the function that uses them.
func maxSizeTrampolinesPPC64(s *Symbol, isTramp bool) uint64 {
// If Thearch.Trampoline is nil, then trampoline support is not available on this arch.
// A trampoline does not need any dependent trampolines.
if Thearch.Trampoline == nil || isTramp {
return 0
}
n := uint64(0)
for ri := range s.R {
r := &s.R[ri]
if r.Type.IsDirectJump() {
n++
}
}
// Trampolines in ppc64 are 4 instructions.
return n * 16
}
// detect too-far jumps in function s, and add trampolines if necessary
// ARM supports trampoline insertion for internal and external linking
// PPC64 & PPC64LE support trampoline insertion for internal linking only
// ARM, PPC64 & PPC64LE support trampoline insertion for internal and external linking
// On PPC64 & PPC64LE the text sections might be split but will still insert trampolines
// where necessary.
func trampoline(ctxt *Link, s *Symbol) {
if Thearch.Trampoline == nil {
return // no need or no support of trampolines on this arch
}
if Linkmode == LinkExternal && SysArch.Family == sys.PPC64 {
return
}
for ri := range s.R {
r := &s.R[ri]
if !r.Type.IsDirectJump() {
@@ -2044,14 +2062,14 @@ func (ctxt *Link) textaddress() {
sect.Vaddr = va
ntramps := 0
for _, sym := range ctxt.Textp {
sect, n, va = assignAddress(ctxt, sect, n, sym, va)
sect, n, va = assignAddress(ctxt, sect, n, sym, va, false)
trampoline(ctxt, sym) // resolve jumps, may add trampolines if jump too far
// lay down trampolines after each function
for ; ntramps < len(ctxt.tramps); ntramps++ {
tramp := ctxt.tramps[ntramps]
sect, n, va = assignAddress(ctxt, sect, n, tramp, va)
sect, n, va = assignAddress(ctxt, sect, n, tramp, va, true)
}
}
@@ -2077,7 +2095,7 @@ func (ctxt *Link) textaddress() {
// assigns address for a text symbol, returns (possibly new) section, its number, and the address
// Note: once we have trampoline insertion support for external linking, this function
// will not need to create new text sections, and so no need to return sect and n.
func assignAddress(ctxt *Link, sect *Section, n int, sym *Symbol, va uint64) (*Section, int, uint64) {
func assignAddress(ctxt *Link, sect *Section, n int, sym *Symbol, va uint64, isTramp bool) (*Section, int, uint64) {
sym.Sect = sect
if sym.Type&obj.SSUB != 0 {
return sect, n, va
@@ -2106,7 +2124,7 @@ func assignAddress(ctxt *Link, sect *Section, n int, sym *Symbol, va uint64) (*S
// Only break at outermost syms.
if SysArch.InFamily(sys.PPC64) && sym.Outer == nil && Iself && Linkmode == LinkExternal && va-sect.Vaddr+funcsize > 0x1c00000 {
if SysArch.InFamily(sys.PPC64) && sym.Outer == nil && Iself && Linkmode == LinkExternal && va-sect.Vaddr+funcsize+maxSizeTrampolinesPPC64(sym, isTramp) > 0x1c00000 {
// Set the length for the previous text section
sect.Length = va - sect.Vaddr

View File

@@ -255,7 +255,7 @@ func decodetypeStructFieldType(s *Symbol, i int) *Symbol {
func decodetypeStructFieldOffs(arch *sys.Arch, s *Symbol, i int) int64 {
off := decodetypeStructFieldArrayOff(s, i)
return int64(decodeInuxi(arch, s.P[off+2*SysArch.PtrSize:], SysArch.IntSize) >> 1)
return int64(decodeInuxi(arch, s.P[off+2*SysArch.PtrSize:], SysArch.IntSize))
}
// InterfaceType.methods.length

View File

@@ -522,13 +522,22 @@ func archrelocaddr(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
// resolve direct jump relocation r in s, and add trampoline if necessary
func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
// Trampolines are created if the branch offset is too large and the linker cannot insert a call stub to handle it.
// For internal linking, trampolines are always created for long calls.
// For external linking, the linker can insert a call stub to handle a long call, but depends on having the TOC address in
// r2. For those build modes with external linking where the TOC address is not maintained in r2, trampolines must be created.
if ld.Linkmode == ld.LinkExternal && (ctxt.DynlinkingGo() || ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE) {
// No trampolines needed since r2 contains the TOC
return
}
t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
switch r.Type {
case obj.R_CALLPOWER:
// If branch offset is too far then create a trampoline.
if int64(int32(t<<6)>>6) != t || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
if (ld.Linkmode == ld.LinkExternal && s.Sect != r.Sym.Sect) || (ld.Linkmode == ld.LinkInternal && int64(int32(t<<6)>>6) != t) || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
var tramp *ld.Symbol
for i := 0; ; i++ {
@@ -552,26 +561,20 @@ func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
t = ld.Symaddr(tramp) + r.Add - (s.Value + int64(r.Off))
// If the offset of the trampoline that has been found is within range, use it.
if int64(int32(t<<6)>>6) == t {
// With internal linking, the trampoline can be used if it is not too far.
// With external linking, the trampoline must be in this section for it to be reused.
if (ld.Linkmode == ld.LinkInternal && int64(int32(t<<6)>>6) == t) || (ld.Linkmode == ld.LinkExternal && s.Sect == tramp.Sect) {
break
}
}
if tramp.Type == 0 {
ctxt.AddTramp(tramp)
tramp.Size = 16 // 4 instructions
tramp.P = make([]byte, tramp.Size)
t = ld.Symaddr(r.Sym) + r.Add
f := t & 0xffff0000
o1 := uint32(0x3fe00000 | (f >> 16)) // lis r31,trampaddr hi (r31 is temp reg)
f = t & 0xffff
o2 := uint32(0x63ff0000 | f) // ori r31,trampaddr lo
o3 := uint32(0x7fe903a6) // mtctr
o4 := uint32(0x4e800420) // bctr
ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)
ld.SysArch.ByteOrder.PutUint32(tramp.P[12:], o4)
if ctxt.DynlinkingGo() || ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE {
// Should have returned for above cases
ld.Errorf(s, "unexpected trampoline for shared or dynamic linking\n")
} else {
ctxt.AddTramp(tramp)
gentramp(tramp, r.Sym, int64(r.Add))
}
}
r.Sym = tramp
r.Add = 0 // This was folded into the trampoline target address
@@ -582,6 +585,42 @@ func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
}
}
func gentramp(tramp, target *ld.Symbol, offset int64) {
// Used for default build mode for an executable
// Address of the call target is generated using
// relocation and doesn't depend on r2 (TOC).
tramp.Size = 16 // 4 instructions
tramp.P = make([]byte, tramp.Size)
t := ld.Symaddr(target) + offset
o1 := uint32(0x3fe00000) // lis r31,targetaddr hi
o2 := uint32(0x3bff0000) // addi r31,targetaddr lo
// With external linking, the target address must be
// relocated using LO and HA
if ld.Linkmode == ld.LinkExternal {
tr := ld.Addrel(tramp)
tr.Off = 0
tr.Type = obj.R_ADDRPOWER
tr.Siz = 8 // generates 2 relocations: HA + LO
tr.Sym = target
tr.Add = offset
} else {
// adjustment needed if lo has sign bit set
// when using addi to compute address
val := uint32((t & 0xffff0000) >> 16)
if t&0x8000 != 0 {
val += 1
}
o1 |= val // hi part of addr
o2 |= uint32(t & 0xffff) // lo part of addr
}
o3 := uint32(0x7fe903a6) // mtctr r31
o4 := uint32(0x4e800420) // bctr
ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)
ld.SysArch.ByteOrder.PutUint32(tramp.P[12:], o4)
}
func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
if ld.Linkmode == ld.LinkExternal {
switch r.Type {

View File

@@ -191,6 +191,10 @@ func matchNameConstraint(domain, constraint string) bool {
// isValid performs validity checks on the c.
func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
if len(c.UnhandledCriticalExtensions) > 0 {
return UnhandledCriticalExtension{}
}
if len(currentChain) > 0 {
child := currentChain[len(currentChain)-1]
if !bytes.Equal(child.RawIssuer, c.RawSubject) {
@@ -279,10 +283,6 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
return c.systemVerify(&opts)
}
if len(c.UnhandledCriticalExtensions) > 0 {
return nil, UnhandledCriticalExtension{}
}
if opts.Roots == nil {
opts.Roots = systemRootsPool()
if opts.Roots == nil {

View File

@@ -263,6 +263,30 @@ var verifyTests = []verifyTest{
errorCallback: expectSubjectIssuerMismatcthError,
},
{
// Test that unknown critical extensions in a leaf cause a
// verify error.
leaf: criticalExtLeafWithExt,
dnsName: "example.com",
intermediates: []string{criticalExtIntermediate},
roots: []string{criticalExtRoot},
currentTime: 1486684488,
systemSkip: true,
errorCallback: expectUnhandledCriticalExtension,
},
{
// Test that unknown critical extensions in an intermediate
// cause a verify error.
leaf: criticalExtLeaf,
dnsName: "example.com",
intermediates: []string{criticalExtIntermediateWithExt},
roots: []string{criticalExtRoot},
currentTime: 1486684488,
systemSkip: true,
errorCallback: expectUnhandledCriticalExtension,
},
}
func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
@@ -330,6 +354,14 @@ func expectSubjectIssuerMismatcthError(t *testing.T, i int, err error) (ok bool)
return true
}
func expectUnhandledCriticalExtension(t *testing.T, i int, err error) (ok bool) {
if _, ok := err.(UnhandledCriticalExtension); !ok {
t.Errorf("#%d: error was not an UnhandledCriticalExtension: %s", i, err)
return false
}
return true
}
func certificateFromPEM(pemBytes string) (*Certificate, error) {
block, _ := pem.Decode([]byte(pemBytes))
if block == nil {
@@ -1379,3 +1411,67 @@ w67CoNRb81dy+4Q1lGpA8ORoLWh5fIq2t2eNGc4qB8vlTIKiESzAwu7u3sRfuWQi
4R+gnfLd37FWflMHwztFbVTuNtPOljCX0LN7KcuoXYlr05RhQrmoN7fQHsrZMNLs
8FVjHdKKu+uPstwd04Uy4BR/H2y1yerN9j/L6ZkMl98iiA==
-----END CERTIFICATE-----`
const criticalExtRoot = `-----BEGIN CERTIFICATE-----
MIIBqzCCAVGgAwIBAgIJAJ+mI/85cXApMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
MDBaMB0xDDAKBgNVBAoTA09yZzENMAsGA1UEAxMEUm9vdDBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABJGp9joiG2QSQA+1FczEDAsWo84rFiP3GTL+n+ugcS6TyNib
gzMsdbJgVi+a33y0SzLZxB+YvU3/4KTk8yKLC+2jejB4MA4GA1UdDwEB/wQEAwIC
BDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB
/zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATAbBgNVHSMEFDASgBBAN9cB+0Av
uBx+VAQnjFkBMAoGCCqGSM49BAMCA0gAMEUCIFeSV00fABFceWR52K+CfIgOHotY
FizzGiLB47hGwjMuAiEA8e0um2Kr8FPQ4wmFKaTRKHMaZizCGl3m+RG5QsE1KWo=
-----END CERTIFICATE-----`
const criticalExtIntermediate = `-----BEGIN CERTIFICATE-----
MIIBszCCAVmgAwIBAgIJAL2kcGZKpzVqMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
MDBaMCUxDDAKBgNVBAoTA09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMFkwEwYH
KoZIzj0CAQYIKoZIzj0DAQcDQgAESqVq92iPEq01cL4o99WiXDc5GZjpjNlzMS1n
rk8oHcVDp4tQRRQG3F4A6dF1rn/L923ha3b0fhDLlAvXZB+7EKN6MHgwDgYDVR0P
AQH/BAQDAgIEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMB
Af8EBTADAQH/MBkGA1UdDgQSBBCMGmiotXbbXVd7H40UsgajMBsGA1UdIwQUMBKA
EEA31wH7QC+4HH5UBCeMWQEwCgYIKoZIzj0EAwIDSAAwRQIhAOhhNRb6KV7h3wbE
cdap8bojzvUcPD78fbsQPCNw1jPxAiBOeAJhlTwpKn9KHpeJphYSzydj9NqcS26Y
xXbdbm27KQ==
-----END CERTIFICATE-----`
const criticalExtLeafWithExt = `-----BEGIN CERTIFICATE-----
MIIBxTCCAWugAwIBAgIJAJZAUtw5ccb1MAoGCCqGSM49BAMCMCUxDDAKBgNVBAoT
A09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMB4XDTE1MDEwMTAwMDAwMFoXDTI1
MDEwMTAwMDAwMFowJDEMMAoGA1UEChMDT3JnMRQwEgYDVQQDEwtleGFtcGxlLmNv
bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF3ABa2+B6gUyg6ayCaRQWYY/+No
6PceLqEavZNUeVNuz7bS74Toy8I7R3bGMkMgbKpLSPlPTroAATvebTXoBaijgYQw
gYEwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
AjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBBRNtBL2vq8nCV3qVp7ycxMMBsGA1Ud
IwQUMBKAEIwaaKi1dttdV3sfjRSyBqMwCgYDUQMEAQH/BAAwCgYIKoZIzj0EAwID
SAAwRQIgVjy8GBgZFiagexEuDLqtGjIRJQtBcf7lYgf6XFPH1h4CIQCT6nHhGo6E
I+crEm4P5q72AnA/Iy0m24l7OvLuXObAmg==
-----END CERTIFICATE-----`
const criticalExtIntermediateWithExt = `-----BEGIN CERTIFICATE-----
MIIB2TCCAX6gAwIBAgIIQD3NrSZtcUUwCgYIKoZIzj0EAwIwHTEMMAoGA1UEChMD
T3JnMQ0wCwYDVQQDEwRSb290MB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAw
MFowPTEMMAoGA1UEChMDT3JnMS0wKwYDVQQDEyRJbnRlcm1lZGlhdGUgd2l0aCBD
cml0aWNhbCBFeHRlbnNpb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQtnmzH
mcRm10bdDBnJE7xQEJ25cLCL5okuEphRR0Zneo6+nQZikoh+UBbtt5GV3Dms7LeP
oF5HOplYDCd8wi/wo4GHMIGEMA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggr
BgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQKxdv
UuQZ6sO3XvBsxgNZ3zAbBgNVHSMEFDASgBBAN9cB+0AvuBx+VAQnjFkBMAoGA1ED
BAEB/wQAMAoGCCqGSM49BAMCA0kAMEYCIQCQzTPd6XKex+OAPsKT/1DsoMsg8vcG
c2qZ4Q0apT/kvgIhAKu2TnNQMIUdcO0BYQIl+Uhxc78dc9h4lO+YJB47pHGx
-----END CERTIFICATE-----`
const criticalExtLeaf = `-----BEGIN CERTIFICATE-----
MIIBzzCCAXWgAwIBAgIJANoWFIlhCI9MMAoGCCqGSM49BAMCMD0xDDAKBgNVBAoT
A09yZzEtMCsGA1UEAxMkSW50ZXJtZWRpYXRlIHdpdGggQ3JpdGljYWwgRXh0ZW5z
aW9uMB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAwMFowJDEMMAoGA1UEChMD
T3JnMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEH
A0IABG1Lfh8A0Ho2UvZN5H0+ONil9c8jwtC0y0xIZftyQE+Fwr9XwqG3rV2g4M1h
GnJa9lV9MPHg8+b85Hixm0ZSw7SjdzB1MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAZBgNVHQ4EEgQQ
UNhY4JhezH9gQYqvDMWrWDAbBgNVHSMEFDASgBArF29S5Bnqw7de8GzGA1nfMAoG
CCqGSM49BAMCA0gAMEUCIQClA3d4tdrDu9Eb5ZBpgyC+fU1xTZB0dKQHz6M5fPZA
2AIgN96lM+CPGicwhN24uQI6flOsO3H0TJ5lNzBYLtnQtlc=
-----END CERTIFICATE-----`

View File

@@ -518,74 +518,6 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
}
}
func TestUnknownCriticalExtension(t *testing.T) {
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("Failed to generate ECDSA key: %s", err)
}
oids := []asn1.ObjectIdentifier{
// This OID is in the PKIX arc, but unknown.
{2, 5, 29, 999999},
// This is a nonsense, unassigned OID.
{1, 2, 3, 4},
}
for _, oid := range oids {
template := Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
CommonName: "foo",
},
NotBefore: time.Unix(1000, 0),
NotAfter: time.Now().AddDate(1, 0, 0),
BasicConstraintsValid: true,
IsCA: true,
KeyUsage: KeyUsageCertSign,
ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
ExtraExtensions: []pkix.Extension{
{
Id: oid,
Critical: true,
Value: nil,
},
},
}
derBytes, err := CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
if err != nil {
t.Fatalf("failed to create certificate: %s", err)
}
cert, err := ParseCertificate(derBytes)
if err != nil {
t.Fatalf("Certificate with unknown critical extension was not parsed: %s", err)
}
roots := NewCertPool()
roots.AddCert(cert)
// Setting Roots ensures that Verify won't delegate to the OS
// library and thus the correct error should always be
// returned.
_, err = cert.Verify(VerifyOptions{Roots: roots})
if err == nil {
t.Fatal("Certificate with unknown critical extension was verified without error")
}
if _, ok := err.(UnhandledCriticalExtension); !ok {
t.Fatalf("Error was %#v, but wanted one of type UnhandledCriticalExtension", err)
}
cert.UnhandledCriticalExtensions = nil
if _, err = cert.Verify(VerifyOptions{Roots: roots}); err != nil {
t.Errorf("Certificate failed to verify after unhandled critical extensions were cleared: %s", err)
}
}
}
// Self-signed certificate using ECDSA with SHA1 & secp256r1
var ecdsaSHA1CertPem = `
-----BEGIN CERTIFICATE-----

View File

@@ -848,7 +848,6 @@ type (
TypeSpec struct {
Doc *CommentGroup // associated documentation; or nil
Name *Ident // type name
Assign token.Pos // position of '=', if any
Type Expr // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
Comment *CommentGroup // line comments; or nil
}

View File

@@ -290,8 +290,7 @@ func defaultContext() Context {
// in all releases >= Go 1.x. Code that requires Go 1.x or later should
// say "+build go1.x", and code that should only be built before Go 1.x
// (perhaps it is the stub to use in that case) should say "+build !go1.x".
// NOTE: If you add to this list, also update the doc comment in doc.go.
c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7", "go1.8", "go1.8.typealias"}
c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7", "go1.8"}
env := os.Getenv("CGO_ENABLED")
if env == "" {

View File

@@ -105,7 +105,6 @@
// - "go1.6", from Go version 1.6 onward
// - "go1.7", from Go version 1.7 onward
// - "go1.8", from Go version 1.8 onward
// - "go1.8.typealias", for Go version 1.8 with aliases
// - any additional words listed in ctxt.BuildTags
//
// If a file's name, after stripping the extension and a possible _test suffix,

View File

@@ -101,7 +101,6 @@ var importerTests = [...]importerTest{
{pkgpath: "unicode", name: "IsUpper", want: "func IsUpper(r rune) bool"},
{pkgpath: "unicode", name: "MaxRune", want: "const MaxRune untyped rune", wantval: "1114111"},
{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
{pkgpath: "alias", name: "IntAlias2", want: "type IntAlias2 = Int"},
}
func TestGoxImporter(t *testing.T) {

View File

@@ -370,41 +370,27 @@ func (p *parser) parseConst(pkg *types.Package) *types.Const {
return types.NewConst(token.NoPos, pkg, name, typ, val)
}
// NamedType = TypeName [ "=" ] Type { Method } .
// TypeName = ExportedName .
// Method = "func" "(" Param ")" Name ParamList ResultList ";" .
func (p *parser) parseNamedType(n int) types.Type {
// TypeName = ExportedName .
func (p *parser) parseTypeName() *types.TypeName {
pkg, name := p.parseExportedName()
scope := pkg.Scope()
if p.tok == '=' {
// type alias
p.next()
typ := p.parseType(pkg)
if obj := scope.Lookup(name); obj != nil {
typ = obj.Type() // use previously imported type
if typ == nil {
p.errorf("%v (type alias) used in cycle", obj)
}
} else {
obj = types.NewTypeName(token.NoPos, pkg, name, typ)
scope.Insert(obj)
}
p.typeMap[n] = typ
return typ
if obj := scope.Lookup(name); obj != nil {
return obj.(*types.TypeName)
}
obj := types.NewTypeName(token.NoPos, pkg, name, nil)
// a named type may be referred to before the underlying type
// is known - set it up
types.NewNamed(obj, nil, nil)
scope.Insert(obj)
return obj
}
// named type
obj := scope.Lookup(name)
if obj == nil {
// a named type may be referred to before the underlying type
// is known - set it up
tname := types.NewTypeName(token.NoPos, pkg, name, nil)
types.NewNamed(tname, nil, nil)
scope.Insert(tname)
obj = tname
}
// NamedType = TypeName Type { Method } .
// Method = "func" "(" Param ")" Name ParamList ResultList ";" .
func (p *parser) parseNamedType(n int) types.Type {
obj := p.parseTypeName()
pkg := obj.Pkg()
typ := obj.Type()
p.typeMap[n] = typ
@@ -423,8 +409,8 @@ func (p *parser) parseNamedType(n int) types.Type {
nt.SetUnderlying(underlying.Underlying())
}
// collect associated methods
for p.tok == scanner.Ident {
// collect associated methods
p.expectKeyword("func")
p.expect('(')
receiver, _ := p.parseParam(pkg)

View File

@@ -1,4 +0,0 @@
v1;
package alias;
pkgpath alias;
type <type 115 "I1" <type 116 interface { M1 (? <type 117 "IntAlias2" = <type 118 "IntAlias" = <type 119 "Int" <type -11>>>>) < type 114>; M2 () <type 1>; }>>;

View File

@@ -98,10 +98,10 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []
// read version specific flags - extend as necessary
switch p.version {
// case 5:
// case 4:
// ...
// fallthrough
case 4, 3, 2, 1:
case 3, 2, 1:
p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
p.trackAllTypes = p.int() != 0
p.posInfoFormat = p.int() != 0
@@ -208,6 +208,7 @@ func (p *importer) pkg() *types.Package {
}
// objTag returns the tag value for each object kind.
// obj must not be a *types.Alias.
func objTag(obj types.Object) int {
switch obj.(type) {
case *types.Const:
@@ -218,6 +219,7 @@ func objTag(obj types.Object) int {
return varTag
case *types.Func:
return funcTag
// Aliases are not exported multiple times, thus we should not see them here.
default:
errorf("unexpected object: %v (%T)", obj, obj) // panics
panic("unreachable")
@@ -235,14 +237,14 @@ func (p *importer) declare(obj types.Object) {
pkg := obj.Pkg()
if alt := pkg.Scope().Insert(obj); alt != nil {
// This can only trigger if we import a (non-type) object a second time.
// Excluding type aliases, this cannot happen because 1) we only import a package
// Excluding aliases, this cannot happen because 1) we only import a package
// once; and b) we ignore compiler-specific export data which may contain
// functions whose inlined function bodies refer to other functions that
// were already imported.
// However, type aliases require reexporting the original type, so we need
// However, aliases require reexporting the original object, so we need
// to allow it (see also the comment in cmd/compile/internal/gc/bimport.go,
// method importer.obj, switch case importing functions).
// TODO(gri) review/update this comment once the gc compiler handles type aliases.
// Note that the original itself cannot be an alias.
if !sameObj(obj, alt) {
errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt)
}
@@ -258,13 +260,6 @@ func (p *importer) obj(tag int) {
val := p.value()
p.declare(types.NewConst(pos, pkg, name, typ, val))
case aliasTag:
// TODO(gri) verify type alias hookup is correct
pos := p.pos()
pkg, name := p.qualifiedName()
typ := p.typ(nil)
p.declare(types.NewTypeName(pos, pkg, name, typ))
case typeTag:
p.typ(nil)
@@ -282,6 +277,19 @@ func (p *importer) obj(tag int) {
sig := types.NewSignature(nil, params, result, isddd)
p.declare(types.NewFunc(pos, pkg, name, sig))
case aliasTag:
pos := p.pos()
name := p.string()
var orig types.Object
if pkg, name := p.qualifiedName(); pkg != nil {
orig = pkg.Scope().Lookup(name)
}
// Alias-related code. Keep for now.
_ = pos
_ = name
_ = orig
// p.declare(types.NewAlias(pos, p.pkgList[0], name, orig))
default:
errorf("unexpected object tag %d", tag)
}
@@ -341,7 +349,9 @@ var (
func (p *importer) qualifiedName() (pkg *types.Package, name string) {
name = p.string()
pkg = p.pkg()
if name != "" {
pkg = p.pkg()
}
return
}
@@ -546,17 +556,17 @@ func (p *importer) fieldList(parent *types.Package) (fields []*types.Var, tags [
fields = make([]*types.Var, n)
tags = make([]string, n)
for i := range fields {
fields[i], tags[i] = p.field(parent)
fields[i] = p.field(parent)
tags[i] = p.string()
}
}
return
}
func (p *importer) field(parent *types.Package) (*types.Var, string) {
func (p *importer) field(parent *types.Package) *types.Var {
pos := p.pos()
pkg, name, alias := p.fieldName(parent)
pkg, name := p.fieldName(parent)
typ := p.typ(parent)
tag := p.string()
anonymous := false
if name == "" {
@@ -568,15 +578,12 @@ func (p *importer) field(parent *types.Package) (*types.Var, string) {
case *types.Named:
name = typ.Obj().Name()
default:
errorf("named base type expected")
errorf("anonymous field expected")
}
anonymous = true
} else if alias {
// anonymous field: we have an explicit name because it's an alias
anonymous = true
}
return types.NewField(pos, pkg, name, typ, anonymous), tag
return types.NewField(pos, pkg, name, typ, anonymous)
}
func (p *importer) methodList(parent *types.Package) (methods []*types.Func) {
@@ -591,42 +598,31 @@ func (p *importer) methodList(parent *types.Package) (methods []*types.Func) {
func (p *importer) method(parent *types.Package) *types.Func {
pos := p.pos()
pkg, name, _ := p.fieldName(parent)
pkg, name := p.fieldName(parent)
params, isddd := p.paramList()
result, _ := p.paramList()
sig := types.NewSignature(nil, params, result, isddd)
return types.NewFunc(pos, pkg, name, sig)
}
func (p *importer) fieldName(parent *types.Package) (pkg *types.Package, name string, alias bool) {
name = p.string()
pkg = parent
func (p *importer) fieldName(parent *types.Package) (*types.Package, string) {
name := p.string()
pkg := parent
if pkg == nil {
// use the imported package instead
pkg = p.pkgList[0]
}
if p.version == 0 && name == "_" {
// version 0 didn't export a package for _ fields
return
return pkg, name
}
switch name {
case "":
// 1) field name matches base type name and is exported: nothing to do
case "?":
// 2) field name matches base type name and is not exported: need package
name = ""
pkg = p.pkg()
case "@":
// 3) field name doesn't match type name (alias)
name = p.string()
alias = true
fallthrough
default:
if !exported(name) {
pkg = p.pkg()
if name != "" && !exported(name) {
if name == "?" {
name = ""
}
pkg = p.pkg()
}
return
return pkg, name
}
func (p *importer) paramList() (*types.Tuple, bool) {
@@ -897,7 +893,7 @@ const (
nilTag // only used by gc (appears in exported inlined function bodies)
unknownTag // not used by gc (only appears in packages with errors)
// Type aliases
// Aliases
aliasTag
)
@@ -921,7 +917,7 @@ var predeclared = []types.Type{
types.Typ[types.Complex128],
types.Typ[types.String],
// basic type aliases
// aliases
types.Universe.Lookup("byte").Type(),
types.Universe.Lookup("rune").Type(),

View File

@@ -2327,10 +2327,7 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.
// (Global identifiers are resolved in a separate phase after parsing.)
spec := &ast.TypeSpec{Doc: doc, Name: ident}
p.declare(spec, nil, p.topScope, ast.Typ, ident)
if p.tok == token.ASSIGN {
spec.Assign = p.pos
p.next()
}
spec.Type = p.parseType()
p.expectSemi() // call before accessing p.linecomment
spec.Comment = p.lineComment

View File

@@ -46,8 +46,6 @@ var valids = []string{
`package p; const (x = 0; y; z)`, // issue 9639
`package p; var _ = map[P]int{P{}:0, {}:1}`,
`package p; var _ = map[*P]int{&P{}:0, {}:1}`,
`package p; type T = int`,
`package p; type (T = p.T; _ = struct{}; x = *T)`,
}
func TestValid(t *testing.T) {

View File

@@ -1447,9 +1447,6 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
} else {
p.print(vtab)
}
if s.Assign.IsValid() {
p.print(token.ASSIGN, blank)
}
p.expr(s.Type)
p.setComment(s.Comment)

View File

@@ -985,18 +985,3 @@ func _(struct {
x int
y int
}) // no extra comma between } and )
// alias declarations
type c0 struct{}
type c1 = C
type c2 = struct{ x int }
type c3 = p.C
type (
s struct{}
a = A
b = A
c = foo
d = interface{}
ddd = p.Foo
)

View File

@@ -999,18 +999,3 @@ func _(struct {
x int
y int
}) // no extra comma between } and )
// alias declarations
type c0 struct{}
type c1 = C
type c2 = struct{ x int}
type c3 = p.C
type (
s struct{}
a = A
b = A
c = foo
d = interface{}
ddd = p.Foo
)

View File

@@ -1295,3 +1295,155 @@ func f(x int) { y := x; print(y) }
}
}
}
// Alias-related code. Keep for now.
/*
func TestAliases(t *testing.T) {
testenv.MustHaveGoBuild(t)
const src = `
package b
import (
"./testdata/alias"
a "./testdata/alias"
"math"
)
const (
c1 = alias.Pi1
c2 => a.Pi1
c3 => a.Pi2
c4 => math.Pi
)
var (
v1 => alias.Default
v2 => a.Default
v3 = f1
)
type (
t1 => alias.Context
t2 => a.Context
)
func f1 => alias.Sin
func f2 => a.Sin
func _() {
assert(c1 == alias.Pi1 && c2 == a.Pi1 && c3 == a.Pi2 && c4 == math.Pi)
assert(c2 == c2 && c2 == c3 && c3 == c4)
v1 = v2 // must be assignable
var _ *t1 = new(t2) // must be assignable
var _ t2 = alias.Default
f1(1) // must be callable
f2(1)
_ = alias.Sin(1)
_ = a.Sin(1)
}
`
if out := compile(t, "testdata", "alias.go"); out != "" {
defer os.Remove(out)
}
DefPredeclaredTestFuncs() // declare assert built-in for testing
mustTypecheck(t, "Aliases", src, nil)
}
func compile(t *testing.T, dirname, filename string) string {
cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", filename)
cmd.Dir = dirname
out, err := cmd.CombinedOutput()
if err != nil {
t.Logf("%s", out)
t.Fatalf("go tool compile %s failed: %s", filename, err)
}
// filename should end with ".go"
return filepath.Join(dirname, filename[:len(filename)-2]+"o")
}
func TestAliasDefUses(t *testing.T) {
testenv.MustHaveGoBuild(t)
const src = `
package p
import(
"go/build"
"go/types"
)
// Defs
const Invalid => types.Invalid
type Struct => types.Struct
var Default => build.Default
func Implements => types.Implements
// Uses
const _ = Invalid
var _ types.Struct = Struct{} // types must be identical
var _ build.Context = Default
var _ = Implements(nil, nil)
`
info := Info{
Defs: make(map[*ast.Ident]Object),
Uses: make(map[*ast.Ident]Object),
}
mustTypecheck(t, "TestAliasDefUses", src, &info)
// verify Defs
defs := map[string]string{
"Invalid": "types.Invalid",
"Struct": "types.Struct",
"Default": "build.Default",
"Implements": "types.Implements",
}
for ident, obj := range info.Defs {
if alias, ok := obj.(*Alias); ok {
if want := defs[ident.Name]; want != "" {
orig := alias.Orig()
if got := orig.Pkg().Name() + "." + orig.Name(); got != want {
t.Errorf("%v: got %v, want %v", ident, got, want)
}
delete(defs, ident.Name) // mark as found
} else {
t.Errorf("unexpected alias def of %v", ident)
}
}
}
if len(defs) != 0 {
t.Errorf("missing aliases: %v", defs)
}
// verify Uses
uses := map[string]string{
"Invalid": "types.Invalid",
"Struct": "types.Struct",
"Default": "build.Default",
"Implements": "types.Implements",
}
for ident, obj := range info.Uses {
if alias, ok := obj.(*Alias); ok {
if want := uses[ident.Name]; want != "" {
orig := alias.Orig()
if got := orig.Pkg().Name() + "." + orig.Name(); got != want {
t.Errorf("%v: got %v, want %v", ident, got, want)
}
delete(uses, ident.Name) // mark as found
} else {
t.Errorf("unexpected alias use of %v", ident)
}
}
}
if len(uses) != 0 {
t.Errorf("missing aliases: %v", defs)
}
}
*/

View File

@@ -275,6 +275,8 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
// so we don't need a "package" mode for operands: package names
// can only appear in qualified identifiers which are mapped to
// selector expressions.
// (see also decl.go: checker.aliasDecl)
// TODO(gri) factor this code out and share with checker.aliasDecl
if ident, ok := e.X.(*ast.Ident); ok {
_, obj := check.scope.LookupParent(ident.Name, check.pos)
if pname, _ := obj.(*PkgName); pname != nil {
@@ -294,6 +296,12 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
// ok to continue
}
check.recordUse(e.Sel, exp)
exp = original(exp)
// avoid further errors if the imported object is an alias that's broken
if exp == nil {
goto Error
}
// Simplified version of the code for *ast.Idents:
// - imported objects are always fully initialized

View File

@@ -68,11 +68,11 @@ var tests = [][]string{
{"testdata/decls1.src"},
{"testdata/decls2a.src", "testdata/decls2b.src"},
{"testdata/decls3.src"},
{"testdata/decls4.src"},
{"testdata/const0.src"},
{"testdata/const1.src"},
{"testdata/constdecl.src"},
{"testdata/vardecl.src"},
//{"testdata/aliasdecl.src"},
{"testdata/expr0.src"},
{"testdata/expr1.src"},
{"testdata/expr2.src"},

View File

@@ -81,10 +81,14 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
check.varDecl(obj, d.lhs, d.typ, d.init)
case *TypeName:
// invalid recursive types are detected via path
check.typeDecl(obj, d.typ, def, path, d.alias)
check.typeDecl(obj, d.typ, def, path)
case *Func:
// functions may be recursive - no need to track dependencies
check.funcDecl(obj, d)
// Alias-related code. Keep for now.
// case *Alias:
// // aliases cannot be recursive - no need to track dependencies
// check.aliasDecl(obj, d)
default:
unreachable()
}
@@ -215,42 +219,33 @@ func (n *Named) setUnderlying(typ Type) {
}
}
func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName, alias bool) {
func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName) {
assert(obj.typ == nil)
// type declarations cannot use iota
assert(check.iota == nil)
if alias {
named := &Named{obj: obj}
def.setUnderlying(named)
obj.typ = named // make sure recursive type declarations terminate
obj.typ = Typ[Invalid]
obj.typ = check.typExpr(typ, nil, append(path, obj))
// determine underlying type of named
check.typExpr(typ, named, append(path, obj))
} else {
named := &Named{obj: obj}
def.setUnderlying(named)
obj.typ = named // make sure recursive type declarations terminate
// determine underlying type of named
check.typExpr(typ, named, append(path, obj))
// The underlying type of named may be itself a named type that is
// incomplete:
//
// type (
// A B
// B *C
// C A
// )
//
// The type of C is the (named) type of A which is incomplete,
// and which has as its underlying type the named type B.
// Determine the (final, unnamed) underlying type by resolving
// any forward chain (they always end in an unnamed type).
named.underlying = underlying(named.underlying)
}
// The underlying type of named may be itself a named type that is
// incomplete:
//
// type (
// A B
// B *C
// C A
// )
//
// The type of C is the (named) type of A which is incomplete,
// and which has as its underlying type the named type B.
// Determine the (final, unnamed) underlying type by resolving
// any forward chain (they always end in an unnamed type).
named.underlying = underlying(named.underlying)
// check and add associated methods
// TODO(gri) It's easy to create pathological cases where the
@@ -273,23 +268,21 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
// spec: "If the base type is a struct type, the non-blank method
// and field names must be distinct."
base, _ := obj.typ.(*Named) // nil if receiver base type is type alias
if base != nil {
if t, _ := base.underlying.(*Struct); t != nil {
for _, fld := range t.fields {
if fld.name != "_" {
assert(mset.insert(fld) == nil)
}
base := obj.typ.(*Named)
if t, _ := base.underlying.(*Struct); t != nil {
for _, fld := range t.fields {
if fld.name != "_" {
assert(mset.insert(fld) == nil)
}
}
}
// Checker.Files may be called multiple times; additional package files
// may add methods to already type-checked types. Add pre-existing methods
// so that we can detect redeclarations.
for _, m := range base.methods {
assert(m.name != "_")
assert(mset.insert(m) == nil)
}
// Checker.Files may be called multiple times; additional package files
// may add methods to already type-checked types. Add pre-existing methods
// so that we can detect redeclarations.
for _, m := range base.methods {
assert(m.name != "_")
assert(mset.insert(m) == nil)
}
// type-check methods
@@ -302,7 +295,7 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
case *Var:
check.errorf(m.pos, "field and method with the same name %s", m.name)
case *Func:
check.errorf(m.pos, "method %s already declared for %s", m.name, obj)
check.errorf(m.pos, "method %s already declared for %s", m.name, base)
default:
unreachable()
}
@@ -310,12 +303,9 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
continue
}
}
// type-check
check.objDecl(m, nil, nil)
// methods with blank _ names cannot be found - don't keep them
if base != nil && m.name != "_" {
if m.name != "_" {
base.methods = append(base.methods, m)
}
}
@@ -343,6 +333,106 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
}
}
// original returns the original Object if obj is an Alias;
// otherwise it returns obj. The result is never an Alias,
// but it may be nil.
func original(obj Object) Object {
// an alias stands for the original object; use that one instead
if alias, _ := obj.(*disabledAlias); alias != nil {
obj = alias.orig
// aliases always refer to non-alias originals
if _, ok := obj.(*disabledAlias); ok {
panic("original is an alias")
}
}
return obj
}
func (check *Checker) aliasDecl(obj *disabledAlias, decl *declInfo) {
assert(obj.typ == nil)
// alias declarations cannot use iota
assert(check.iota == nil)
// assume alias is invalid to start with
obj.typ = Typ[Invalid]
// rhs must be package-qualified identifer pkg.sel (see also call.go: checker.selector)
// TODO(gri) factor this code out and share with checker.selector
rhs := decl.init
var pkg *Package
var sel *ast.Ident
if sexpr, ok := rhs.(*ast.SelectorExpr); ok {
if ident, ok := sexpr.X.(*ast.Ident); ok {
_, obj := check.scope.LookupParent(ident.Name, check.pos)
if pname, _ := obj.(*PkgName); pname != nil {
assert(pname.pkg == check.pkg)
check.recordUse(ident, pname)
pname.used = true
pkg = pname.imported
sel = sexpr.Sel
}
}
}
if pkg == nil {
check.errorf(rhs.Pos(), "invalid alias: %v is not a package-qualified identifier", rhs)
return
}
// qualified identifier must denote an exported object
orig := pkg.scope.Lookup(sel.Name)
if orig == nil || !orig.Exported() {
if !pkg.fake {
check.errorf(rhs.Pos(), "%s is not exported by package %s", sel.Name, pkg.name)
}
return
}
check.recordUse(sel, orig)
orig = original(orig)
// avoid further errors if the imported object is an alias that's broken
if orig == nil {
return
}
// An alias declaration must not refer to package unsafe.
if orig.Pkg() == Unsafe {
check.errorf(rhs.Pos(), "invalid alias: %s refers to package unsafe (%v)", obj.Name(), orig)
return
}
// The original must be of the same kind as the alias declaration.
var why string
switch obj.kind {
case token.CONST:
if _, ok := orig.(*Const); !ok {
why = "constant"
}
case token.TYPE:
if _, ok := orig.(*TypeName); !ok {
why = "type"
}
case token.VAR:
if _, ok := orig.(*Var); !ok {
why = "variable"
}
case token.FUNC:
if _, ok := orig.(*Func); !ok {
why = "function"
}
default:
unreachable()
}
if why != "" {
check.errorf(rhs.Pos(), "invalid alias: %v is not a %s", orig, why)
return
}
// alias is valid
obj.typ = orig.Type()
obj.orig = orig
}
func (check *Checker) declStmt(decl ast.Decl) {
pkg := check.pkg
@@ -450,7 +540,7 @@ func (check *Checker) declStmt(decl ast.Decl) {
// the innermost containing block."
scopePos := s.Name.Pos()
check.declare(check.scope, s.Name, obj, scopePos)
check.typeDecl(obj, s.Type, nil, nil, s.Assign.IsValid())
check.typeDecl(obj, s.Type, nil, nil)
default:
check.invalidAST(s.Pos(), "const, type, or var declaration expected")

View File

@@ -239,10 +239,10 @@ func fib(x int) int {
// type S string:
// defined at fib.go:4:6
// used at 6:23
// type int:
// type int int:
// defined at -
// used at 8:12, 8:17
// type string:
// type string string:
// defined at -
// used at 4:8
// var b S:

View File

@@ -67,22 +67,24 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
}
typ, isPtr := deref(T)
named, _ := typ.(*Named)
// *typ where typ is an interface has no methods.
if isPtr && IsInterface(typ) {
return
if isPtr {
utyp := typ
if named != nil {
utyp = named.underlying
}
if _, ok := utyp.(*Interface); ok {
return
}
}
// Start with typ as single entry at shallowest depth.
current := []embeddedType{{typ, nil, isPtr, false}}
// If typ is not a named type, insert a nil type instead.
current := []embeddedType{{named, nil, isPtr, false}}
// Named types that we have seen already, allocated lazily.
// Used to avoid endless searches in case of recursive types.
// Since only Named types can be used for recursive types, we
// only need to track those.
// (If we ever allow type aliases to construct recursive types,
// we must use type identity rather than pointer equality for
// the map key comparison, as we do in consolidateMultiples.)
// named types that we have seen already, allocated lazily
var seen map[*Named]bool
// search current depth
@@ -91,12 +93,11 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
// look for (pkg, name) in all types at current depth
for _, e := range current {
typ := e.typ
// If we have a named type, we may have associated methods.
// Look for those first.
if named, _ := typ.(*Named); named != nil {
if seen[named] {
// The very first time only, e.typ may be nil.
// In this case, we don't have a named type and
// we simply continue with the underlying type.
if e.typ != nil {
if seen[e.typ] {
// We have seen this type before, at a more shallow depth
// (note that multiples of this type at the current depth
// were consolidated before). The type at that depth shadows
@@ -107,10 +108,10 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
if seen == nil {
seen = make(map[*Named]bool)
}
seen[named] = true
seen[e.typ] = true
// look for a matching attached method
if i, m := lookupMethod(named.methods, pkg, name); m != nil {
if i, m := lookupMethod(e.typ.methods, pkg, name); m != nil {
// potential match
assert(m.typ != nil)
index = concat(e.index, i)
@@ -123,7 +124,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
}
// continue with underlying type
typ = named.underlying
typ = e.typ.underlying
}
switch t := typ.(type) {
@@ -146,15 +147,16 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
// we have a name collision on the same depth; in either
// case we don't need to look further).
// Embedded fields are always of the form T or *T where
// T is a type name. If e.typ appeared multiple times at
// T is a named type. If e.typ appeared multiple times at
// this depth, f.typ appears multiple times at the next
// depth.
if obj == nil && f.anonymous {
// Ignore embedded basic types - only user-defined
// named types can have methods or struct fields.
typ, isPtr := deref(f.typ)
// TODO(gri) optimization: ignore types that can't
// have fields or methods (only Named, Struct, and
// Interface types need to be considered).
next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
if t, _ := typ.(*Named); t != nil {
next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
}
}
}
@@ -191,12 +193,12 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
return nil, nil, false // not found
}
// embeddedType represents an embedded type
// embeddedType represents an embedded named type
type embeddedType struct {
typ Type
index []int // embedded field indices, starting with index at depth 0
indirect bool // if set, there was a pointer indirection on the path to this field
multiples bool // if set, typ appears multiple times at this depth
typ *Named // nil means use the outer typ variable instead
index []int // embedded field indices, starting with index at depth 0
indirect bool // if set, there was a pointer indirection on the path to this field
multiples bool // if set, typ appears multiple times at this depth
}
// consolidateMultiples collects multiple list entries with the same type
@@ -207,10 +209,10 @@ func consolidateMultiples(list []embeddedType) []embeddedType {
return list // at most one entry - nothing to do
}
n := 0 // number of entries w/ unique type
prev := make(map[Type]int) // index at which type was previously seen
n := 0 // number of entries w/ unique type
prev := make(map[*Named]int) // index at which type was previously seen
for _, e := range list {
if i, found := lookupType(prev, e.typ); found {
if i, found := prev[e.typ]; found {
list[i].multiples = true
// ignore this entry
} else {
@@ -222,21 +224,6 @@ func consolidateMultiples(list []embeddedType) []embeddedType {
return list[:n]
}
func lookupType(m map[Type]int, typ Type) (int, bool) {
// fast path: maybe the types are equal
if i, found := m[typ]; found {
return i, true
}
for t, i := range m {
if Identical(t, typ) {
return i, true
}
}
return 0, false
}
// MissingMethod returns (nil, false) if V implements T, otherwise it
// returns a missing method required by T and whether it is missing or
// just has the wrong type.

View File

@@ -72,22 +72,24 @@ func NewMethodSet(T Type) *MethodSet {
var base methodSet
typ, isPtr := deref(T)
named, _ := typ.(*Named)
// *typ where typ is an interface has no methods.
if isPtr && IsInterface(typ) {
return &emptyMethodSet
if isPtr {
utyp := typ
if named != nil {
utyp = named.underlying
}
if _, ok := utyp.(*Interface); ok {
return &emptyMethodSet
}
}
// Start with typ as single entry at shallowest depth.
current := []embeddedType{{typ, nil, isPtr, false}}
// If typ is not a named type, insert a nil type instead.
current := []embeddedType{{named, nil, isPtr, false}}
// Named types that we have seen already, allocated lazily.
// Used to avoid endless searches in case of recursive types.
// Since only Named types can be used for recursive types, we
// only need to track those.
// (If we ever allow type aliases to construct recursive types,
// we must use type identity rather than pointer equality for
// the map key comparison, as we do in consolidateMultiples.)
// named types that we have seen already, allocated lazily
var seen map[*Named]bool
// collect methods at current depth
@@ -99,12 +101,11 @@ func NewMethodSet(T Type) *MethodSet {
var mset methodSet
for _, e := range current {
typ := e.typ
// If we have a named type, we may have associated methods.
// Look for those first.
if named, _ := typ.(*Named); named != nil {
if seen[named] {
// The very first time only, e.typ may be nil.
// In this case, we don't have a named type and
// we simply continue with the underlying type.
if e.typ != nil {
if seen[e.typ] {
// We have seen this type before, at a more shallow depth
// (note that multiples of this type at the current depth
// were consolidated before). The type at that depth shadows
@@ -115,12 +116,12 @@ func NewMethodSet(T Type) *MethodSet {
if seen == nil {
seen = make(map[*Named]bool)
}
seen[named] = true
seen[e.typ] = true
mset = mset.add(named.methods, e.index, e.indirect, e.multiples)
mset = mset.add(e.typ.methods, e.index, e.indirect, e.multiples)
// continue with underlying type
typ = named.underlying
typ = e.typ.underlying
}
switch t := typ.(type) {
@@ -129,15 +130,16 @@ func NewMethodSet(T Type) *MethodSet {
fset = fset.add(f, e.multiples)
// Embedded fields are always of the form T or *T where
// T is a type name. If typ appeared multiple times at
// T is a named type. If typ appeared multiple times at
// this depth, f.Type appears multiple times at the next
// depth.
if f.anonymous {
// Ignore embedded basic types - only user-defined
// named types can have methods or struct fields.
typ, isPtr := deref(f.typ)
// TODO(gri) optimization: ignore types that can't
// have fields or methods (only Named, Struct, and
// Interface types need to be considered).
next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
if t, _ := typ.(*Named); t != nil {
next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
}
}
}

View File

@@ -25,7 +25,7 @@ type Object interface {
Name() string // package local object name
Type() Type // object type
Exported() bool // reports whether the name starts with a capital letter
Id() string // object name if exported, qualified name if not exported (see func Id)
Id() string // object id (see Id below)
// String returns a human-readable string of the object.
String() string
@@ -64,10 +64,15 @@ func Id(pkg *Package, name string) string {
// inside a package and outside a package - which breaks some
// tests)
path := "_"
// pkg is nil for objects in Universe scope and possibly types
// introduced via Eval (see also comment in object.sameId)
if pkg != nil && pkg.path != "" {
// TODO(gri): shouldn't !ast.IsExported(name) => pkg != nil be an precondition?
// if pkg == nil {
// panic("nil package in lookup of unexported name")
// }
if pkg != nil {
path = pkg.path
if path == "" {
path = "_"
}
}
return path + "." + name
}
@@ -149,7 +154,7 @@ func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val constant.V
func (obj *Const) Val() constant.Value { return obj.val }
func (*Const) isDependency() {} // a constant may be a dependency of an initialization expression
// A TypeName represents a name for a (named or alias) type.
// A TypeName represents a declared type.
type TypeName struct {
object
}
@@ -158,26 +163,6 @@ func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
return &TypeName{object{nil, pos, pkg, name, typ, 0, token.NoPos}}
}
// IsAlias reports whether obj is an alias name for a type.
func (obj *TypeName) IsAlias() bool {
switch t := obj.typ.(type) {
case nil:
return false
case *Basic:
// Any user-defined type name for a basic type is an alias for a
// basic type (because basic types are pre-declared in the Universe
// scope, outside any package scope), and so is any type name with
// a different name than the name of the basic type it refers to.
// Additionaly, we need to look for "byte" and "rune" because they
// are aliases but have the same names (for better error messages).
return obj.pkg != nil || t.name != obj.name || t == universeByte || t == universeRune
case *Named:
return obj != t.obj
default:
return true
}
}
// A Variable represents a declared variable (including function parameters and results, and struct fields).
type Var struct {
object
@@ -230,6 +215,28 @@ func (obj *Func) FullName() string {
func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
func (*Func) isDependency() {} // a function may be a dependency of an initialization expression
// An Alias represents a declared alias.
type disabledAlias struct {
object
orig Object // aliased constant, type, variable, or function; never an alias
kind token.Token // token.CONST, token.TYPE, token.VAR, or token.FUNC (only needed during resolve phase)
}
func disabledNewAlias(pos token.Pos, pkg *Package, name string, orig Object) *disabledAlias {
var typ Type = Typ[Invalid]
if orig != nil {
typ = orig.Type()
}
// No need to set a valid Alias.kind - that field is only used during identifier
// resolution (1st type-checker pass). We could store the field outside but it's
// easier to keep it here.
return &disabledAlias{object{nil, pos, pkg, name, typ, 0, token.NoPos}, orig, token.ILLEGAL}
}
// Orig returns the aliased object, or nil if there was an error.
// The returned object is never an Alias.
func (obj *disabledAlias) disabledOrig() Object { return obj.orig }
// A Label represents a declared label.
type Label struct {
object
@@ -257,9 +264,7 @@ type Nil struct {
}
func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
var tname *TypeName
typ := obj.Type()
switch obj := obj.(type) {
case *PkgName:
fmt.Fprintf(buf, "package %s", obj.Name())
@@ -272,8 +277,8 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
buf.WriteString("const")
case *TypeName:
tname = obj
buf.WriteString("type")
typ = typ.Underlying()
case *Var:
if obj.isField {
@@ -290,6 +295,10 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
}
return
// Alias-related code. Keep for now.
// case *Alias:
// buf.WriteString("alias")
case *Label:
buf.WriteString("label")
typ = nil
@@ -313,27 +322,10 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
writePackage(buf, obj.Pkg(), qf)
}
buf.WriteString(obj.Name())
if typ == nil {
return
if typ != nil {
buf.WriteByte(' ')
WriteType(buf, typ, qf)
}
if tname != nil {
// We have a type object: Don't print anything more for
// basic types since there's no more information (names
// are the same; see also comment in TypeName.IsAlias).
if _, ok := typ.(*Basic); ok {
return
}
if tname.IsAlias() {
buf.WriteString(" =")
} else {
typ = typ.Underlying()
}
}
buf.WriteByte(' ')
WriteType(buf, typ, qf)
}
func writePackage(buf *bytes.Buffer, pkg *Package, qf Qualifier) {
@@ -361,14 +353,15 @@ func ObjectString(obj Object, qf Qualifier) string {
return buf.String()
}
func (obj *PkgName) String() string { return ObjectString(obj, nil) }
func (obj *Const) String() string { return ObjectString(obj, nil) }
func (obj *TypeName) String() string { return ObjectString(obj, nil) }
func (obj *Var) String() string { return ObjectString(obj, nil) }
func (obj *Func) String() string { return ObjectString(obj, nil) }
func (obj *Label) String() string { return ObjectString(obj, nil) }
func (obj *Builtin) String() string { return ObjectString(obj, nil) }
func (obj *Nil) String() string { return ObjectString(obj, nil) }
func (obj *PkgName) String() string { return ObjectString(obj, nil) }
func (obj *Const) String() string { return ObjectString(obj, nil) }
func (obj *TypeName) String() string { return ObjectString(obj, nil) }
func (obj *Var) String() string { return ObjectString(obj, nil) }
func (obj *Func) String() string { return ObjectString(obj, nil) }
func (obj *disabledAlias) String() string { return ObjectString(obj, nil) }
func (obj *Label) String() string { return ObjectString(obj, nil) }
func (obj *Builtin) String() string { return ObjectString(obj, nil) }
func (obj *Nil) String() string { return ObjectString(obj, nil) }
func writeFuncName(buf *bytes.Buffer, f *Func, qf Qualifier) {
if f.typ != nil {

View File

@@ -1,43 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package types
import "testing"
func TestIsAlias(t *testing.T) {
check := func(obj *TypeName, want bool) {
if got := obj.IsAlias(); got != want {
t.Errorf("%v: got IsAlias = %v; want %v", obj, got, want)
}
}
// predeclared types
for _, name := range Universe.Names() {
if obj, _ := Universe.Lookup(name).(*TypeName); obj != nil {
check(obj, name == "byte" || name == "rune")
}
}
// various other types
pkg := NewPackage("p", "p")
t1 := NewTypeName(0, pkg, "t1", nil)
n1 := NewNamed(t1, new(Struct), nil)
for _, test := range []struct {
name *TypeName
alias bool
}{
{NewTypeName(0, nil, "t0", nil), false}, // no type yet
{NewTypeName(0, pkg, "t0", nil), false}, // no type yet
{t1, false}, // type name refers to named type and vice versa
{NewTypeName(0, nil, "t2", new(Interface)), true}, // type name refers to unnamed type
{NewTypeName(0, pkg, "t3", n1), true}, // type name refers to named type with different type name
{NewTypeName(0, nil, "t4", Typ[Int32]), true}, // type name refers to basic type with different name
{NewTypeName(0, nil, "int32", Typ[Int32]), false}, // type name refers to basic type with same name
{NewTypeName(0, pkg, "int32", Typ[Int32]), true}, // type name is declared in user-defined package (outside Universe)
{NewTypeName(0, nil, "rune", Typ[Rune]), true}, // type name refers to basic type rune which is an alias already
} {
check(test.name, test.alias)
}
}

View File

@@ -139,7 +139,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
case *Basic:
// Basic types are singletons except for the rune and byte
// aliases, thus we cannot solely rely on the x == y check
// above. See also comment in TypeName.IsAlias.
// above.
if y, ok := y.(*Basic); ok {
return x.kind == y.kind
}

View File

@@ -14,14 +14,13 @@ import (
"unicode"
)
// A declInfo describes a package-level const, type, var, or func declaration.
// A declInfo describes a package-level const, type, var, func, or alias declaration.
type declInfo struct {
file *Scope // scope of file containing this declaration
lhs []*Var // lhs of n:1 variable declarations, or nil
typ ast.Expr // type, or nil
init ast.Expr // init/orig expression, or nil
fdecl *ast.FuncDecl // func declaration, or nil
alias bool // type alias declaration
// The deps field tracks initialization expression dependencies.
// As a special (overloaded) case, it also tracks dependencies of
@@ -275,6 +274,13 @@ func (check *Checker) collectObjects() {
check.declare(fileScope, nil, obj, token.NoPos)
}
// Alias-related code. Keep for now.
// case *ast.AliasSpec:
// obj := NewAlias(s.Name.Pos(), pkg, s.Name.Name, nil)
// obj.typ = nil // unresolved
// obj.kind = d.Tok
// check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, init: s.Orig})
case *ast.ValueSpec:
switch d.Tok {
case token.CONST:
@@ -341,7 +347,7 @@ func (check *Checker) collectObjects() {
case *ast.TypeSpec:
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, typ: s.Type, alias: s.Assign.IsValid()})
check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, typ: s.Type})
default:
check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)

View File

@@ -1,150 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// type aliases
package decls4
type (
T0 [10]int
T1 []byte
T2 struct {
x int
}
T3 interface{
m() T2
}
T4 func(int, T0) chan T2
)
type (
Ai = int
A0 = T0
A1 = T1
A2 = T2
A3 = T3
A4 = T4
A10 = [10]int
A11 = []byte
A12 = struct {
x int
}
A13 = interface{
m() A2
}
A14 = func(int, A0) chan A2
)
// check assignment compatibility due to equality of types
var (
xi_ int
ai Ai = xi_
x0 T0
a0 A0 = x0
x1 T1
a1 A1 = x1
x2 T2
a2 A2 = x2
x3 T3
a3 A3 = x3
x4 T4
a4 A4 = x4
)
// alias receiver types
func (Ai /* ERROR "invalid receiver" */) m1() {}
func (T0) m1() {}
func (A0) m1 /* ERROR already declared */ () {}
func (A0) m2 () {}
func (A3 /* ERROR invalid receiver */ ) m1 () {}
func (A10 /* ERROR invalid receiver */ ) m1() {}
// x0 has methods m1, m2 declared via receiver type names T0 and A0
var _ interface{ m1(); m2() } = x0
// cycles
type (
C2 /* ERROR illegal cycle */ = C2
C3 /* ERROR illegal cycle */ = C4
C4 = C3
C5 struct {
f *C6
}
C6 = C5
C7 /* ERROR illegal cycle */ struct {
f C8
}
C8 = C7
)
// embedded fields
var (
s0 struct { T0 }
s1 struct { A0 } = s0 /* ERROR cannot use */ // embedded field names are different
)
// embedding and lookup of fields and methods
func _(s struct{A0}) { s.A0 = x0 }
type eX struct{xf int}
func (eX) xm()
type eY = struct{eX} // field/method set of eY includes xf, xm
type eZ = *struct{eX} // field/method set of eZ includes xf, xm
type eA struct {
eX // eX contributes xf, xm to eA
}
type eA2 struct {
*eX // *eX contributes xf, xm to eA
}
type eB struct {
eY // eY contributes xf, xm to eB
}
type eB2 struct {
*eY // *eY contributes xf, xm to eB
}
type eC struct {
eZ // eZ contributes xf, xm to eC
}
var (
_ = eA{}.xf
_ = eA{}.xm
_ = eA2{}.xf
_ = eA2{}.xm
_ = eB{}.xf
_ = eB{}.xm
_ = eB2{}.xf
_ = eB2{}.xm
_ = eC{}.xf
_ = eC{}.xm
)
// ambiguous selectors due to embedding via type aliases
type eD struct {
eY
eZ
}
var (
_ = eD /* ERROR ambiguous selector */ {}.xf
_ = eD /* ERROR ambiguous selector */ {}.xm
)
var (
_ interface{ xm() } = eD /* ERROR missing method xm */ {}
)

View File

@@ -56,7 +56,6 @@ func RelativeTo(pkg *Package) Qualifier {
// This flag is exported in the x/tools/go/types package. We don't
// need it at the moment in the std repo and so we don't export it
// anymore. We should eventually try to remove it altogether.
// TODO(gri) remove this
var gcCompatibilityMode bool
// TypeString returns the string representation of typ.

View File

@@ -45,6 +45,17 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeNa
delete(check.unusedDotImports[scope], pkg)
}
// Alias-related code. Keep for now.
// An alias stands for the original object; use that one instead.
// TODO(gri) We should be able to factor out the Typ[Invalid] test.
// if alias, _ := obj.(*Alias); alias != nil {
// obj = original(obj)
// if obj == nil || typ == Typ[Invalid] {
// return
// }
// assert(typ == obj.Type())
// }
switch obj := obj.(type) {
case *PkgName:
check.errorf(e.Pos(), "use of package %s not in selector", obj.name)
@@ -650,41 +661,47 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
}
} else {
// anonymous field
// spec: "An embedded type must be specified as a type name T or as a pointer
// to a non-interface type name *T, and T itself may not be a pointer type."
pos := f.Type.Pos()
name := anonymousFieldIdent(f.Type)
if name == nil {
check.invalidAST(pos, "anonymous field type %s has no name", f.Type)
continue
}
pos := f.Type.Pos()
t, isPtr := deref(typ)
// Because we have a name, typ must be of the form T or *T, where T is the name
// of a (named or alias) type, and t (= deref(typ)) must be the type of T.
switch t := t.Underlying().(type) {
switch t := t.(type) {
case *Basic:
if t == Typ[Invalid] {
// error was reported before
continue
}
// unsafe.Pointer is treated like a regular pointer
if t.kind == UnsafePointer {
check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
continue
}
add(f, name, true, pos)
case *Pointer:
check.errorf(pos, "anonymous field type cannot be a pointer")
continue
case *Interface:
if isPtr {
check.errorf(pos, "anonymous field type cannot be a pointer to an interface")
case *Named:
// spec: "An embedded type must be specified as a type name
// T or as a pointer to a non-interface type name *T, and T
// itself may not be a pointer type."
switch u := t.underlying.(type) {
case *Basic:
// unsafe.Pointer is treated like a regular pointer
if u.kind == UnsafePointer {
check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
continue
}
case *Pointer:
check.errorf(pos, "anonymous field type cannot be a pointer")
continue
case *Interface:
if isPtr {
check.errorf(pos, "anonymous field type cannot be a pointer to an interface")
continue
}
}
add(f, name, true, pos)
default:
check.invalidAST(pos, "anonymous field type %s must be named", typ)
}
add(f, name, true, pos)
}
}
@@ -697,10 +714,7 @@ func anonymousFieldIdent(e ast.Expr) *ast.Ident {
case *ast.Ident:
return e
case *ast.StarExpr:
// *T is valid, but **T is not
if _, ok := e.X.(*ast.StarExpr); !ok {
return anonymousFieldIdent(e.X)
}
return anonymousFieldIdent(e.X)
case *ast.SelectorExpr:
return e.Sel
}

View File

@@ -1487,6 +1487,26 @@ func TestSqrt(t *testing.T) {
}
}
// We can't test this together with the other Exp tests above because
// it requires a different receiver setup.
func TestIssue22830(t *testing.T) {
one := new(Int).SetInt64(1)
base, _ := new(Int).SetString("84555555300000000000", 10)
mod, _ := new(Int).SetString("66666670001111111111", 10)
want, _ := new(Int).SetString("17888885298888888889", 10)
var tests = []int64{
0, 1, -1,
}
for _, n := range tests {
m := NewInt(n)
if got := m.Exp(base, one, mod); got.Cmp(want) != 0 {
t.Errorf("(%v).Exp(%s, 1, %s) = %s, want %s", n, base, mod, got, want)
}
}
}
func BenchmarkSqrt(b *testing.B) {
n, _ := new(Int).SetString("1"+strings.Repeat("0", 1001), 10)
b.ResetTimer()

View File

@@ -575,8 +575,8 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
// determine if z can be reused
// TODO(gri) should find a better solution - this if statement
// is very costly (see e.g. time pidigits -s -n 10000)
if alias(z, uIn) || alias(z, v) {
z = nil // z is an alias for uIn or v - cannot reuse
if alias(z, u) || alias(z, uIn) || alias(z, v) {
z = nil // z is an alias for u or uIn or v - cannot reuse
}
q = z.make(m + 1)

View File

@@ -225,6 +225,8 @@ func dialClosedPort() (actual, expected time.Duration) {
// but other platforms should be instantaneous.
if runtime.GOOS == "windows" {
expected = 1500 * time.Millisecond
} else if runtime.GOOS == "darwin" {
expected = 150 * time.Millisecond
} else {
expected = 95 * time.Millisecond
}

View File

@@ -1091,7 +1091,12 @@ func TestLinuxSendfile(t *testing.T) {
// and will error out if we specify that with `-e trace='.
syscalls = "sendfile"
case "mips64":
t.Skip("TODO: update this test to be robust against various versions of strace on mips64. See golang.org/issue/33430")
t.Skip("TODO: update this test to be robust against various versions of strace on mips64. See golang.org/issue/18008")
}
// Attempt to run strace, and skip on failure - this test requires SYS_PTRACE.
if err := exec.Command("strace", "-f", "-q", "-e", "trace="+syscalls, os.Args[0], "-test.run=^$").Run(); err != nil {
t.Skipf("skipping; failed to run strace: %v", err)
}
var buf bytes.Buffer

View File

@@ -503,21 +503,26 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) {
}
}
func getmacSpeaksEnglish(t *testing.T) bool {
// check that getmac exists as a powershell command, and that it
// speaks English.
func checkGetmac(t *testing.T) {
out, err := runCmd("getmac", "/?")
if err != nil {
if strings.Contains(err.Error(), "term 'getmac' is not recognized as the name of a cmdlet") {
t.Skipf("getmac not available")
}
t.Fatal(err)
}
return bytes.Contains(out, []byte("network adapters on a system"))
if !bytes.Contains(out, []byte("network adapters on a system")) {
t.Skipf("skipping test on non-English system")
}
}
func TestInterfaceHardwareAddrWithGetmac(t *testing.T) {
if isWindowsXP(t) {
t.Skip("Windows XP does not have powershell command")
}
if !getmacSpeaksEnglish(t) {
t.Skip("English version of getmac required for this test")
}
checkGetmac(t)
ift, err := Interfaces()
if err != nil {

View File

@@ -44,26 +44,29 @@ type plainAuth struct {
}
// PlainAuth returns an Auth that implements the PLAIN authentication
// mechanism as defined in RFC 4616.
// The returned Auth uses the given username and password to authenticate
// on TLS connections to host and act as identity. Usually identity will be
// left blank to act as username.
// mechanism as defined in RFC 4616. The returned Auth uses the given
// username and password to authenticate to host and act as identity.
// Usually identity should be the empty string, to act as username.
//
// PlainAuth will only send the credentials if the connection is using TLS
// or is connected to localhost. Otherwise authentication will fail with an
// error, without sending the credentials.
func PlainAuth(identity, username, password, host string) Auth {
return &plainAuth{identity, username, password, host}
}
func isLocalhost(name string) bool {
return name == "localhost" || name == "127.0.0.1" || name == "::1"
}
func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) {
if !server.TLS {
advertised := false
for _, mechanism := range server.Auth {
if mechanism == "PLAIN" {
advertised = true
break
}
}
if !advertised {
return "", nil, errors.New("unencrypted connection")
}
// Must have TLS, or else localhost server.
// Note: If TLS is not true, then we can't trust ANYTHING in ServerInfo.
// In particular, it doesn't matter if the server advertises PLAIN auth.
// That might just be the attacker saying
// "it's ok, you can trust me with your password."
if !server.TLS && !isLocalhost(server.Name) {
return "", nil, errors.New("unencrypted connection")
}
if server.Name != a.host {
return "", nil, errors.New("wrong host name")

View File

@@ -67,6 +67,7 @@ func NewClient(conn net.Conn, host string) (*Client, error) {
return nil, err
}
c := &Client{Text: text, conn: conn, serverName: host, localName: "localhost"}
_, c.tls = conn.(*tls.Conn)
return c, nil
}

View File

@@ -60,29 +60,41 @@ testLoop:
}
func TestAuthPlain(t *testing.T) {
auth := PlainAuth("foo", "bar", "baz", "servername")
tests := []struct {
server *ServerInfo
err string
authName string
server *ServerInfo
err string
}{
{
server: &ServerInfo{Name: "servername", TLS: true},
authName: "servername",
server: &ServerInfo{Name: "servername", TLS: true},
},
{
// Okay; explicitly advertised by server.
server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}},
// OK to use PlainAuth on localhost without TLS
authName: "localhost",
server: &ServerInfo{Name: "localhost", TLS: false},
},
{
server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}},
err: "unencrypted connection",
// NOT OK on non-localhost, even if server says PLAIN is OK.
// (We don't know that the server is the real server.)
authName: "servername",
server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}},
err: "unencrypted connection",
},
{
server: &ServerInfo{Name: "attacker", TLS: true},
err: "wrong host name",
authName: "servername",
server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}},
err: "unencrypted connection",
},
{
authName: "servername",
server: &ServerInfo{Name: "attacker", TLS: true},
err: "wrong host name",
},
}
for i, tt := range tests {
auth := PlainAuth("foo", "bar", "baz", tt.authName)
_, _, err := auth.Start(tt.server)
got := ""
if err != nil {
@@ -350,6 +362,53 @@ HELO localhost
QUIT
`
func TestNewClientWithTLS(t *testing.T) {
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
if err != nil {
t.Fatalf("loadcert: %v", err)
}
config := tls.Config{Certificates: []tls.Certificate{cert}}
ln, err := tls.Listen("tcp", "127.0.0.1:0", &config)
if err != nil {
ln, err = tls.Listen("tcp", "[::1]:0", &config)
if err != nil {
t.Fatalf("server: listen: %s", err)
}
}
go func() {
conn, err := ln.Accept()
if err != nil {
t.Fatalf("server: accept: %s", err)
return
}
defer conn.Close()
_, err = conn.Write([]byte("220 SIGNS\r\n"))
if err != nil {
t.Fatalf("server: write: %s", err)
return
}
}()
config.InsecureSkipVerify = true
conn, err := tls.Dial("tcp", ln.Addr().String(), &config)
if err != nil {
t.Fatalf("client: dial: %s", err)
}
defer conn.Close()
client, err := NewClient(conn, ln.Addr().String())
if err != nil {
t.Fatalf("smtp: newclient: %s", err)
}
if !client.tls {
t.Errorf("client.tls Got: %t Expected: %t", client.tls, true)
}
}
func TestHello(t *testing.T) {
if len(helloServer) != len(helloClient) {

View File

@@ -404,6 +404,8 @@ func TestDirectorySymbolicLink(t *testing.T) {
func TestNetworkSymbolicLink(t *testing.T) {
testenv.MustHaveSymlink(t)
const _NERR_ServerNotStarted = syscall.Errno(2114)
dir, err := ioutil.TempDir("", "TestNetworkSymbolicLink")
if err != nil {
t.Fatal(err)
@@ -454,6 +456,9 @@ func TestNetworkSymbolicLink(t *testing.T) {
if err == syscall.ERROR_ACCESS_DENIED {
t.Skip("you don't have enough privileges to add network share")
}
if err == _NERR_ServerNotStarted {
t.Skip(_NERR_ServerNotStarted.Error())
}
t.Fatal(err)
}
defer func() {

View File

@@ -3731,7 +3731,7 @@ func checkSameType(t *testing.T, x, y interface{}) {
func TestArrayOf(t *testing.T) {
// check construction and use of type not in binary
tests := []struct {
for _, table := range []struct {
n int
value func(i int) interface{}
comparable bool
@@ -3809,9 +3809,7 @@ func TestArrayOf(t *testing.T) {
comparable: true,
want: "[{0 0} {1 1} {2 2} {3 3} {4 4} {5 5} {6 6} {7 7} {8 8} {9 9}]",
},
}
for _, table := range tests {
} {
at := ArrayOf(table.n, TypeOf(table.value(0)))
v := New(at).Elem()
vok := New(at).Elem()
@@ -4177,58 +4175,50 @@ func TestStructOfExportRules(t *testing.T) {
f()
}
tests := []struct {
for i, test := range []struct {
field StructField
mustPanic bool
exported bool
}{
{
field: StructField{Name: "S1", Anonymous: true, Type: TypeOf(S1{})},
exported: true,
field: StructField{Name: "", Type: TypeOf(S1{})},
mustPanic: false,
exported: true,
},
{
field: StructField{Name: "S1", Anonymous: true, Type: TypeOf((*S1)(nil))},
exported: true,
field: StructField{Name: "", Type: TypeOf((*S1)(nil))},
mustPanic: false,
exported: true,
},
{
field: StructField{Name: "s2", Anonymous: true, Type: TypeOf(s2{})},
field: StructField{Name: "", Type: TypeOf(s2{})},
mustPanic: false,
exported: false,
},
{
field: StructField{Name: "", Type: TypeOf((*s2)(nil))},
mustPanic: false,
exported: false,
},
{
field: StructField{Name: "", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
mustPanic: true,
exported: true,
},
{
field: StructField{Name: "s2", Anonymous: true, Type: TypeOf((*s2)(nil))},
field: StructField{Name: "", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
mustPanic: true,
exported: true,
},
{
field: StructField{Name: "Name", Type: nil, PkgPath: ""},
field: StructField{Name: "", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
mustPanic: true,
exported: false,
},
{
field: StructField{Name: "", Type: TypeOf(S1{}), PkgPath: ""},
mustPanic: true,
},
{
field: StructField{Name: "S1", Anonymous: true, Type: TypeOf(S1{}), PkgPath: "other/pkg"},
mustPanic: true,
},
{
field: StructField{Name: "S1", Anonymous: true, Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
mustPanic: true,
},
{
field: StructField{Name: "s2", Anonymous: true, Type: TypeOf(s2{}), PkgPath: "other/pkg"},
mustPanic: true,
},
{
field: StructField{Name: "s2", Anonymous: true, Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
mustPanic: true,
},
{
field: StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"},
mustPanic: true,
},
{
field: StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"},
field: StructField{Name: "", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
mustPanic: true,
exported: false,
},
{
field: StructField{Name: "S", Type: TypeOf(S1{})},
@@ -4236,68 +4226,81 @@ func TestStructOfExportRules(t *testing.T) {
exported: true,
},
{
field: StructField{Name: "S", Type: TypeOf((*S1)(nil))},
exported: true,
field: StructField{Name: "S", Type: TypeOf((*S1)(nil))},
mustPanic: false,
exported: true,
},
{
field: StructField{Name: "S", Type: TypeOf(s2{})},
exported: true,
field: StructField{Name: "S", Type: TypeOf(s2{})},
mustPanic: false,
exported: true,
},
{
field: StructField{Name: "S", Type: TypeOf((*s2)(nil))},
exported: true,
field: StructField{Name: "S", Type: TypeOf((*s2)(nil))},
mustPanic: false,
exported: true,
},
{
field: StructField{Name: "s", Type: TypeOf(S1{})},
mustPanic: true,
exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf((*S1)(nil))},
mustPanic: true,
exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf(s2{})},
mustPanic: true,
exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf((*s2)(nil))},
mustPanic: true,
exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
mustPanic: true, // TODO(sbinet): creating a name with a package path
exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
mustPanic: true, // TODO(sbinet): creating a name with a package path
exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
mustPanic: true, // TODO(sbinet): creating a name with a package path
exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
mustPanic: true, // TODO(sbinet): creating a name with a package path
exported: false,
},
{
field: StructField{Name: "", Type: TypeOf(ΦType{})},
mustPanic: true,
mustPanic: false,
exported: true,
},
{
field: StructField{Name: "", Type: TypeOf(φType{})},
mustPanic: true,
mustPanic: false,
exported: false,
},
{
field: StructField{Name: "Φ", Type: TypeOf(0)},
exported: true,
field: StructField{Name: "Φ", Type: TypeOf(0)},
mustPanic: false,
exported: true,
},
{
field: StructField{Name: "φ", Type: TypeOf(0)},
exported: false,
field: StructField{Name: "φ", Type: TypeOf(0)},
mustPanic: false,
exported: false,
},
}
for i, test := range tests {
} {
testPanic(i, test.mustPanic, func() {
typ := StructOf([]StructField{test.field})
if typ == nil {
@@ -4307,7 +4310,7 @@ func TestStructOfExportRules(t *testing.T) {
field := typ.Field(0)
n := field.Name
if n == "" {
panic("field.Name must not be empty")
n = field.Type.Name()
}
exported := isExported(n)
if exported != test.exported {
@@ -4385,7 +4388,7 @@ func TestStructOfGenericAlg(t *testing.T) {
{Name: "S1", Type: st1},
})
tests := []struct {
for _, table := range []struct {
rt Type
idx []int
}{
@@ -4466,9 +4469,7 @@ func TestStructOfGenericAlg(t *testing.T) {
),
idx: []int{2},
},
}
for _, table := range tests {
} {
v1 := New(table.rt).Elem()
v2 := New(table.rt).Elem()
@@ -4570,21 +4571,18 @@ func TestStructOfWithInterface(t *testing.T) {
type Iface interface {
Get() int
}
tests := []struct {
name string
for i, table := range []struct {
typ Type
val Value
impl bool
}{
{
name: "StructI",
typ: TypeOf(StructI(want)),
val: ValueOf(StructI(want)),
impl: true,
},
{
name: "StructI",
typ: PtrTo(TypeOf(StructI(want))),
typ: PtrTo(TypeOf(StructI(want))),
val: ValueOf(func() interface{} {
v := StructI(want)
return &v
@@ -4592,8 +4590,7 @@ func TestStructOfWithInterface(t *testing.T) {
impl: true,
},
{
name: "StructIPtr",
typ: PtrTo(TypeOf(StructIPtr(want))),
typ: PtrTo(TypeOf(StructIPtr(want))),
val: ValueOf(func() interface{} {
v := StructIPtr(want)
return &v
@@ -4601,7 +4598,6 @@ func TestStructOfWithInterface(t *testing.T) {
impl: true,
},
{
name: "StructIPtr",
typ: TypeOf(StructIPtr(want)),
val: ValueOf(StructIPtr(want)),
impl: false,
@@ -4611,16 +4607,13 @@ func TestStructOfWithInterface(t *testing.T) {
// val: ValueOf(StructI(want)),
// impl: true,
// },
}
for i, table := range tests {
} {
rt := StructOf(
[]StructField{
{
Name: table.name,
Anonymous: true,
PkgPath: "",
Type: table.typ,
Name: "",
PkgPath: "",
Type: table.typ,
},
},
)
@@ -6066,7 +6059,6 @@ func TestSwapper(t *testing.T) {
want: []pairPtr{{5, 6, &c}, {3, 4, &b}, {1, 2, &a}},
},
}
for i, tt := range tests {
inStr := fmt.Sprint(tt.in)
Swapper(tt.in)(tt.i, tt.j)
@@ -6092,36 +6084,3 @@ func TestUnaddressableField(t *testing.T) {
lv.Set(rv)
})
}
type Tint int
type Tint2 = Tint
type Talias1 struct {
byte
uint8
int
int32
rune
}
type Talias2 struct {
Tint
Tint2
}
func TestAliasNames(t *testing.T) {
t1 := Talias1{byte: 1, uint8: 2, int: 3, int32: 4, rune: 5}
out := fmt.Sprintf("%#v", t1)
want := "reflect_test.Talias1{byte:0x1, uint8:0x2, int:3, int32:4, rune:5}"
if out != want {
t.Errorf("Talias1 print:\nhave: %s\nwant: %s", out, want)
}
t2 := Talias2{Tint: 1, Tint2: 2}
out = fmt.Sprintf("%#v", t2)
want = "reflect_test.Talias2{Tint:1, Tint2:2}"
if out != want {
t.Errorf("Talias2 print:\nhave: %s\nwant: %s", out, want)
}
}

View File

@@ -417,17 +417,9 @@ type sliceType struct {
// Struct field
type structField struct {
name name // name is always non-empty
typ *rtype // type of field
offsetAnon uintptr // byte offset of field<<1 | isAnonymous
}
func (f *structField) offset() uintptr {
return f.offsetAnon >> 1
}
func (f *structField) anon() bool {
return f.offsetAnon&1 != 0
name name // name is empty for embedded fields
typ *rtype // type of field
offset uintptr // byte offset of field within struct
}
// structType represents a struct type.
@@ -1223,8 +1215,16 @@ func (t *structType) Field(i int) (f StructField) {
}
p := &t.fields[i]
f.Type = toType(p.typ)
f.Name = p.name.name()
f.Anonymous = p.anon()
if name := p.name.name(); name != "" {
f.Name = name
} else {
t := f.Type
if t.Kind() == Ptr {
t = t.Elem()
}
f.Name = t.Name()
f.Anonymous = true
}
if !p.name.isExported() {
f.PkgPath = p.name.pkgPath()
if f.PkgPath == "" {
@@ -1234,7 +1234,7 @@ func (t *structType) Field(i int) (f StructField) {
if tag := p.name.tag(); tag != "" {
f.Tag = StructTag(tag)
}
f.Offset = p.offset()
f.Offset = p.offset
// NOTE(rsc): This is the only allocation in the interface
// presented by a reflect.Type. It would be nice to avoid,
@@ -1321,15 +1321,19 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel
visited[t] = true
for i := range t.fields {
f := &t.fields[i]
// Find name and (for anonymous field) type for field f.
fname := f.name.name()
// Find name and type for field f.
var fname string
var ntyp *rtype
if f.anon() {
if name := f.name.name(); name != "" {
fname = name
} else {
// Anonymous field of type T or *T.
// Name taken from type.
ntyp = f.typ
if ntyp.Kind() == Ptr {
ntyp = ntyp.Elem().common()
}
fname = ntyp.Name()
}
// Does it match?
@@ -1386,11 +1390,13 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) {
if name != "" {
for i := range t.fields {
tf := &t.fields[i]
if tf.name.name() == name {
return t.Field(i), true
}
if tf.anon() {
tfname := tf.name.name()
if tfname == "" {
hasAnon = true
continue
}
if tfname == name {
return t.Field(i), true
}
}
}
@@ -1689,7 +1695,7 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
if cmpTags && tf.name.tag() != vf.name.tag() {
return false
}
if tf.offsetAnon != vf.offsetAnon {
if tf.offset != vf.offset {
return false
}
if !tf.name.isExported() {
@@ -2398,9 +2404,6 @@ func StructOf(fields []StructField) Type {
lastzero := uintptr(0)
repr = append(repr, "struct {"...)
for i, field := range fields {
if field.Name == "" {
panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no name")
}
if field.Type == nil {
panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type")
}
@@ -2413,11 +2416,13 @@ func StructOf(fields []StructField) Type {
hasPtr = true
}
name := ""
// Update string and hash
name := f.name.name()
hash = fnv1(hash, []byte(name)...)
repr = append(repr, (" " + name)...)
if f.anon() {
if f.name.nameLen() > 0 {
hash = fnv1(hash, []byte(f.name.name())...)
repr = append(repr, (" " + f.name.name())...)
name = f.name.name()
} else {
// Embedded field
if f.typ.Kind() == Ptr {
// Embedded ** and *interface{} are illegal
@@ -2425,7 +2430,11 @@ func StructOf(fields []StructField) Type {
if k := elem.Kind(); k == Ptr || k == Interface {
panic("reflect.StructOf: illegal anonymous field type " + ft.String())
}
name = elem.String()
} else {
name = ft.String()
}
// TODO(sbinet) check for syntactically impossible type names?
switch f.typ.Kind() {
case Interface:
@@ -2557,12 +2566,11 @@ func StructOf(fields []StructField) Type {
comparable = comparable && (ft.alg.equal != nil)
hashable = hashable && (ft.alg.hash != nil)
offset := align(size, uintptr(ft.align))
f.offset = align(size, uintptr(ft.align))
if ft.align > typalign {
typalign = ft.align
}
size = offset + ft.size
f.offsetAnon |= offset << 1
size = f.offset + ft.size
if ft.size == 0 {
lastzero = size
@@ -2754,7 +2762,7 @@ func StructOf(fields []StructField) Type {
typ.alg.hash = func(p unsafe.Pointer, seed uintptr) uintptr {
o := seed
for _, ft := range typ.fields {
pi := unsafe.Pointer(uintptr(p) + ft.offset())
pi := unsafe.Pointer(uintptr(p) + ft.offset)
o = ft.typ.alg.hash(pi, o)
}
return o
@@ -2764,8 +2772,8 @@ func StructOf(fields []StructField) Type {
if comparable {
typ.alg.equal = func(p, q unsafe.Pointer) bool {
for _, ft := range typ.fields {
pi := unsafe.Pointer(uintptr(p) + ft.offset())
qi := unsafe.Pointer(uintptr(q) + ft.offset())
pi := unsafe.Pointer(uintptr(p) + ft.offset)
qi := unsafe.Pointer(uintptr(q) + ft.offset)
if !ft.typ.alg.equal(pi, qi) {
return false
}
@@ -2787,27 +2795,25 @@ func StructOf(fields []StructField) Type {
}
func runtimeStructField(field StructField) structField {
if field.PkgPath != "" {
panic("reflect.StructOf: StructOf does not allow unexported fields")
exported := field.PkgPath == ""
if field.Name == "" {
t := field.Type.(*rtype)
if t.Kind() == Ptr {
t = t.Elem().(*rtype)
}
exported = t.nameOff(t.str).isExported()
} else if exported {
b0 := field.Name[0]
if ('a' <= b0 && b0 <= 'z') || b0 == '_' {
panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but has no PkgPath")
}
}
// Best-effort check for misuse.
// Since PkgPath is empty, not much harm done if Unicode lowercase slips through.
c := field.Name[0]
if 'a' <= c && c <= 'z' || c == '_' {
panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath")
}
offsetAnon := uintptr(0)
if field.Anonymous {
offsetAnon |= 1
}
resolveReflectType(field.Type.common()) // install in runtime
_ = resolveReflectType(field.Type.common())
return structField{
name: newName(field.Name, string(field.Tag), "", true),
typ: field.Type.common(),
offsetAnon: offsetAnon,
name: newName(field.Name, string(field.Tag), field.PkgPath, exported),
typ: field.Type.common(),
offset: 0,
}
}
@@ -2830,7 +2836,7 @@ func typeptrdata(t *rtype) uintptr {
}
}
f := st.fields[field]
return f.offset() + f.typ.ptrdata
return f.offset + f.typ.ptrdata
default:
panic("reflect.typeptrdata: unexpected type, " + t.String())
@@ -3204,7 +3210,7 @@ func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
tt := (*structType)(unsafe.Pointer(t))
for i := range tt.fields {
f := &tt.fields[i]
addTypeBits(bv, offset+f.offset(), f.typ)
addTypeBits(bv, offset+f.offset, f.typ)
}
}
}

View File

@@ -769,7 +769,7 @@ func (v Value) Field(i int) Value {
fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
// Using an unexported field forces flagRO.
if !field.name.isExported() {
if field.anon() {
if field.name.name() == "" {
fl |= flagEmbedRO
} else {
fl |= flagStickyRO
@@ -780,7 +780,7 @@ func (v Value) Field(i int) Value {
// In the former case, we want v.ptr + offset.
// In the latter case, we must have field.offset = 0,
// so v.ptr + field.offset is still okay.
ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset())
ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset)
return Value{typ, ptr, fl}
}

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