Compare commits

..

22 Commits

Author SHA1 Message Date
Russ Cox
fab5e254b2 [release-branch.go1.8] go1.8.5
TESTING: go1.8.5rc4

DO NOT REVIEW

Change-Id: I7c6cf169e84329a31d2d9dc4c52d5c29e80482c9
2017-10-20 12:43:01 -04:00
Michael Hudson-Doyle
03d6e3722a [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>
2017-10-20 12:42:12 -04:00
Adam Langley
bc7fb45f5a [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>
2017-10-20 12:41:29 -04:00
Lynn Boger
0c629da1b3 [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>
2017-10-20 12:40:43 -04:00
Russ Cox
f5fe0e3542 [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>
2017-10-20 12:39:59 -04:00
Ian Lance Taylor
179d09dd07 [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>
2017-10-20 12:39:14 -04:00
Jeff
c3a62a2c6b [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>
2017-10-20 12:38:29 -04:00
Author Name
a0be3483e1 [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>
2017-10-20 12:37:45 -04:00
Elias Naur
41161ce666 [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>
2017-10-20 12:36:59 -04:00
pvoicu
20176bce82 [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>
2017-10-20 12:36:12 -04:00
Brad Fitzpatrick
dd9b69d838 [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>
2017-10-20 12:35:27 -04:00
Cherry Zhang
b571ae17ec [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>
2017-10-20 12:34:41 -04:00
David Chase
6643c252bf [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>
2017-10-20 12:33:53 -04:00
Kenny Grant
64f53b2573 [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>
2017-10-20 12:33:04 -04:00
Michael Munday
235fe5d072 [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>
2017-10-19 16:37:32 -04:00
Brad Fitzpatrick
2ef4a8565b [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>
2017-10-19 16:26:20 -04: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
98 changed files with 1563 additions and 1622 deletions

View File

@@ -1 +1 @@
go1.8.3.typealias
go1.8.5rc4

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

@@ -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;

View File

@@ -340,16 +340,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 +356,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 +367,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 +460,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 +924,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

@@ -154,7 +154,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 +171,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 +187,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 +259,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 +467,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:

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

@@ -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

@@ -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()
@@ -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")

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

@@ -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}
}

View File

@@ -531,7 +531,7 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
return
}
for _, f := range st.fields {
cgoCheckArg(f.typ, add(p, f.offset()), true, top, msg)
cgoCheckArg(f.typ, add(p, f.offset), true, top, msg)
}
case kindPtr, kindUnsafePointer:
if indir {

View File

@@ -169,7 +169,7 @@ func TestPeriodicGC(t *testing.T) {
// slack if things are slow.
var numGCs uint32
const want = 2
for i := 0; i < 20 && numGCs < want; i++ {
for i := 0; i < 200 && numGCs < want; i++ {
time.Sleep(5 * time.Millisecond)
// Test that periodic GC actually happened.

View File

@@ -100,7 +100,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$8
MOVL AX, 0(SP)
MOVL $1000, AX // usec to nsec
MULL DX
MOVL DX, 4(SP)
MOVL AX, 4(SP)
// pselect6(0, 0, 0, 0, &ts, 0)
MOVL $308, AX

View File

@@ -390,13 +390,9 @@ type ptrtype struct {
}
type structfield struct {
name name
typ *_type
offsetAnon uintptr
}
func (f *structfield) offset() uintptr {
return f.offsetAnon >> 1
name name
typ *_type
offset uintptr
}
type structtype struct {
@@ -654,7 +650,7 @@ func typesEqual(t, v *_type) bool {
if tf.name.tag() != vf.name.tag() {
return false
}
if tf.offsetAnon != vf.offsetAnon {
if tf.offset != vf.offset {
return false
}
}

View File

@@ -1,104 +0,0 @@
// errorcheck
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test basic restrictions on type aliases.
package p
import (
"reflect"
. "reflect"
)
type T0 struct{}
// Valid type alias declarations.
type _ = T0
type _ = int
type _ = struct{}
type _ = reflect.Value
type _ = Value
type (
A0 = T0
A1 = int
A2 = struct{}
A3 = reflect.Value
A4 = Value
A5 = Value
N0 A0
)
// Methods can be declared on the original named type and the alias.
func (T0) m1() {} // GCCGO_ERROR "previous"
func (*T0) m1() {} // ERROR "method redeclared: T0\.m1|redefinition of .m1."
func (A0) m1() {} // ERROR "T0\.m1 redeclared in this block|redefinition of .m1."
func (A0) m1() {} // ERROR "T0\.m1 redeclared in this block|redefinition of .m1."
func (A0) m2() {}
// Type aliases and the original type name can be used interchangeably.
var _ A0 = T0{}
var _ T0 = A0{}
// But aliases and original types cannot be used with new types based on them.
var _ N0 = T0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
var _ N0 = A0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
var _ A5 = Value{}
var _ interface {
m1()
m2()
} = T0{}
var _ interface {
m1()
m2()
} = A0{}
func _() {
type _ = T0
type _ = int
type _ = struct{}
type _ = reflect.Value
type _ = Value
type (
A0 = T0
A1 = int
A2 = struct{}
A3 = reflect.Value
A4 = Value
A5 Value
N0 A0
)
var _ A0 = T0{}
var _ T0 = A0{}
var _ N0 = T0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
var _ N0 = A0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
var _ A5 = Value{} // ERROR "cannot use reflect\.Value literal \(type reflect.Value\) as type A5 in assignment|incompatible type"
}
// Invalid type alias declarations.
type _ = reflect.ValueOf // ERROR "reflect.ValueOf is not a type|expected type"
func (A1) m() {} // ERROR "cannot define new methods on non-local type int|may not define methods on non-local type"
func (A2) m() {} // ERROR "invalid receiver type"
func (A3) m() {} // ERROR "cannot define new methods on non-local type reflect.Value|may not define methods on non-local type"
func (A4) m() {} // ERROR "reflect.Value.m redeclared in this block" "cannot define new methods on non-local type reflect.Value|may not define methods on non-local type"
type B1 = struct{}
func (B1) m() {} // ERROR "m redeclared in this block" "invalid receiver type"
// TODO(gri) expand

View File

@@ -1,42 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package a
import "go/build"
type (
Float64 = float64
Rune = rune
)
type (
Int int
IntAlias = Int
IntAlias2 = IntAlias
S struct {
Int
IntAlias
IntAlias2
}
)
type (
Context = build.Context
)
type (
I1 interface {
M1(IntAlias2) Float64
M2() Context
}
I2 = interface {
M1(Int) float64
M2() build.Context
}
)
var i1 I1
var i2 I2 = i1

View File

@@ -1,26 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package b
import (
"./a"
. "go/build"
)
func F(x float64) a.Float64 {
return x
}
type MyContext = Context // = build.Context
var C a.Context = Default
type S struct{}
func (S) M1(x a.IntAlias) float64 { return a.Float64(x) }
func (S) M2() Context { return Default }
var _ a.I1 = S{}
var _ a.I2 = S{}

View File

@@ -1,25 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"./a"
"./b"
)
func main() {
var _ float64 = b.F(0)
var _ a.Rune = int32(0)
// embedded types can have different names but the same types
var s a.S
s.Int = 1
s.IntAlias = s.Int
s.IntAlias2 = s.Int
// aliases denote identical types across packages
var c a.Context = b.C
var _ b.MyContext = c
}

View File

@@ -1,7 +0,0 @@
// rundir
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ignored

View File

@@ -1,26 +0,0 @@
// compile
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
type (
a = b
b struct {
*a
}
c struct {
*d
}
d = c
e = f
f = g
g = []h
h i
i = j
j = e
)

View File

@@ -1,22 +0,0 @@
// errorcheck
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
type T struct{}
type A = T
type B = T
func (T) m() {}
func (T) m() {} // ERROR "redeclared"
func (A) m() {} // ERROR "redeclared"
func (A) m() {} // ERROR "redeclared"
func (B) m() {} // ERROR "redeclared"
func (B) m() {} // ERROR "redeclared"
func (*T) m() {} // ERROR "redeclared"
func (*A) m() {} // ERROR "redeclared"
func (*B) m() {} // ERROR "redeclared"

View File

@@ -0,0 +1,34 @@
// run
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
var a uint8
//go:noinline
func f() {
b := int8(func() int32 { return -1 }())
a = uint8(b)
if int32(a) != 255 {
// Failing case prints 'got 255 expected 255'
println("got", a, "expected 255")
}
}
//go:noinline
func g() {
b := int8(func() uint32 { return 0xffffffff }())
a = uint8(b)
if int32(a) != 255 {
// Failing case prints 'got 255 expected 255'
println("got", a, "expected 255")
}
}
func main() {
f()
g()
}