aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/gccgo_install.html4
-rw-r--r--doc/go1.4.txt4
-rw-r--r--doc/go1compat.html8
-rw-r--r--doc/go_faq.html4
-rw-r--r--doc/go_spec.html11
-rw-r--r--misc/makerelease/windows/installer.wxs6
-rw-r--r--src/cmd/gc/walk.c8
-rw-r--r--src/cmd/go/build.go1
-rw-r--r--src/cmd/go/get.go11
-rw-r--r--src/cmd/go/vcs.go50
-rw-r--r--src/encoding/csv/writer.go16
-rw-r--r--src/encoding/csv/writer_test.go11
-rw-r--r--src/net/http/pprof/pprof.go4
-rw-r--r--src/net/lookup.go51
-rw-r--r--src/net/singleflight.go66
-rw-r--r--src/runtime/symtab.go11
-rw-r--r--src/unsafe/unsafe.go3
-rw-r--r--test/fixedbugs/issue8947.go53
18 files changed, 265 insertions, 57 deletions
diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html
index 4c1a8c2f57..acb315a0ac 100644
--- a/doc/gccgo_install.html
+++ b/doc/gccgo_install.html
@@ -42,6 +42,10 @@ identical to Go 1.1. The GCC 4.8.2 release includes a complete Go
1.1.2 implementation.
</p>
+<p>
+The GCC 4.9 releases include a complete Go 1.2 implementation.
+</p>
+
<h2 id="Source_code">Source code</h2>
<p>
diff --git a/doc/go1.4.txt b/doc/go1.4.txt
index ae52562df9..b9d8ade245 100644
--- a/doc/go1.4.txt
+++ b/doc/go1.4.txt
@@ -24,8 +24,10 @@ bufio: handling of empty tokens at EOF changed, may require scanner change (CL 1
compress/flate, compress/gzip, compress/zlib: Reset support (https://codereview.appspot.com/97140043)
crypto/tls: add support for ALPN (RFC 7301) (CL 108710046)
crypto/tls: support programmatic selection of server certificates (CL 107400043)
+encoding/asn1: optional elements with a default value will now only be omitted if they have that value (CL 86960045)
flag: it is now an error to set a flag multiple times (CL 156390043)
fmt: print type *map[T]T as &map[k:v] (CL 154870043)
+encoding/csv: do not quote empty strings, quote \. (CL 164760043)
encoding/gob: remove unsafe (CL 102680045)
misc: deleted editor support; refer to https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins instead (CL 105470043)
net/http: add Request.BasicAuth method (CL 76540043)
@@ -46,6 +48,6 @@ testing: add TestMain support (CL 148770043)
text/scanner: add IsIdentRune field of Scanner. (CL 108030044)
text/template: allow comparison of signed and unsigned integers (CL 149780043)
time: use the micro symbol (ยต (U+00B5)) to print microsecond duration (CL 105030046)
-encoding/asn1: optional elements with a default value will now only be omitted if they have that value (CL 86960045)
+unsafe: document the existing situation that unsafe programs are not go1-guaranteed (CL 162060043)
go.sys subrepo created: http://golang.org/s/go1.4-syscall
diff --git a/doc/go1compat.html b/doc/go1compat.html
index 04a6c1124b..94c48d2ce3 100644
--- a/doc/go1compat.html
+++ b/doc/go1compat.html
@@ -104,6 +104,14 @@ outside of tests, and using it may cause a program to fail
to compile in future releases.
</li>
+<li>
+Use of package <code>unsafe</code>. Packages that import
+<a href="/pkg/unsafe/"><code>unsafe</code></a>
+may depend on internal properties of the Go implementation.
+We reserve the right to make changes to the implementation
+that may break such programs.
+</li>
+
</ul>
<p>
diff --git a/doc/go_faq.html b/doc/go_faq.html
index ec3689aeb0..9aac058388 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -1115,7 +1115,7 @@ error but the situation can still be confusing, because sometimes a
<a href="#different_method_sets">pointer
is necessary to satisfy an interface</a>.
The insight is that although a pointer to a concrete type can satisfy
-an interface, with one exception <em>a pointer to an interface can never satisfy a interface</em>.
+an interface, with one exception <em>a pointer to an interface can never satisfy an interface</em>.
</p>
<p>
@@ -1356,7 +1356,7 @@ to speed it up.
</p>
<p>
-Go's goroutine scheduler is not as good as it needs to be. In future, it
+Go's goroutine scheduler is not as good as it needs to be. In the future, it
should recognize such cases and optimize its use of OS threads. For now,
<code>GOMAXPROCS</code> should be set on a per-application basis.
</p>
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 97effeaa4a..ad645c1ffc 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
<!--{
"Title": "The Go Programming Language Specification",
- "Subtitle": "Version of October 16, 2014",
+ "Subtitle": "Version of October 23, 2014",
"Path": "/ref/spec"
}-->
@@ -6207,8 +6207,8 @@ type Error interface {
The built-in package <code>unsafe</code>, known to the compiler,
provides facilities for low-level programming including operations
that violate the type system. A package using <code>unsafe</code>
-must be vetted manually for type safety. The package provides the
-following interface:
+must be vetted manually for type safety and may not be portable.
+The package provides the following interface:
</p>
<pre class="grammar">
@@ -6223,10 +6223,11 @@ func Sizeof(variable ArbitraryType) uintptr
</pre>
<p>
-Any pointer or value of <a href="#Types">underlying type</a> <code>uintptr</code> can be converted to
-a <code>Pointer</code> type and vice versa.
A <code>Pointer</code> is a <a href="#Pointer_types">pointer type</a> but a <code>Pointer</code>
value may not be <a href="#Address_operators">dereferenced</a>.
+Any pointer or value of <a href="#Types">underlying type</a> <code>uintptr</code> can be converted to
+a <code>Pointer</code> type and vice versa.
+The effect of converting between <code>Pointer</code> and <code>uintptr</code> is implementation-defined.
</p>
<pre>
diff --git a/misc/makerelease/windows/installer.wxs b/misc/makerelease/windows/installer.wxs
index 66e0913ba8..01178e2651 100644
--- a/misc/makerelease/windows/installer.wxs
+++ b/misc/makerelease/windows/installer.wxs
@@ -39,9 +39,9 @@
<Property Id="ARPCOMMENTS" Value="The Go programming language is a fast, statically typed, compiled language that feels like a dynamically typed, interpreted language." />
<Property Id="ARPCONTACT" Value="golang-nuts@googlegroups.com" />
-<Property Id="ARPHELPLINK" Value="golang.org/doc/community.html" />
-<Property Id="ARPREADME" Value="golang.org" />
-<Property Id="ARPURLINFOABOUT" Value="golang.org" />
+<Property Id="ARPHELPLINK" Value="https://golang.org/help/" />
+<Property Id="ARPREADME" Value="https://golang.org" />
+<Property Id="ARPURLINFOABOUT" Value="https://golang.org" />
<Property Id="LicenseAccepted">1</Property>
<Icon Id="gopher.ico" SourceFile="images\gopher.ico"/>
<Property Id="ARPPRODUCTICON" Value="gopher.ico" />
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 2520343bfd..eaa0440552 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -614,7 +614,7 @@ walkexpr(Node **np, NodeList **init)
if(oaslit(n, init))
goto ret;
- if(n->right == N)
+ if(n->right == N || iszero(n->right) && !flag_race)
goto ret;
switch(n->right->op) {
@@ -1390,12 +1390,6 @@ walkexpr(Node **np, NodeList **init)
case OMAPLIT:
case OSTRUCTLIT:
case OPTRLIT:
- // NOTE(rsc): Race detector cannot handle seeing
- // a STRUCTLIT or ARRAYLIT representing a zero value,
- // so make a temporary for those always in race mode.
- // Otherwise, leave zero values in place.
- if(iszero(n) && !flag_race)
- goto ret;
var = temp(n->type);
anylit(0, n, var, init);
n = var;
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index 49b84709e2..79a27116a1 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1945,6 +1945,7 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []
}
ldflags = append(ldflags, afiles...)
ldflags = append(ldflags, cgoldflags...)
+ ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
ldflags = append(ldflags, p.CgoLDFLAGS...)
if usesCgo && goos == "linux" {
ldflags = append(ldflags, "-Wl,-E")
diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go
index 2640339414..b8eac5c1ef 100644
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -272,8 +272,15 @@ func downloadPackage(p *Package) error {
dir := filepath.Join(p.build.SrcRoot, rootPath)
if remote, err := vcs.remoteRepo(vcs, dir); err == nil {
if rr, err := repoRootForImportPath(p.ImportPath); err == nil {
- if remote != rr.repo {
- return fmt.Errorf("%s is from %s, should be from %s", dir, remote, rr.repo)
+ repo := rr.repo
+ if rr.vcs.resolveRepo != nil {
+ resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
+ if err == nil {
+ repo = resolved
+ }
+ }
+ if remote != repo {
+ return fmt.Errorf("%s is from %s, should be from %s", dir, remote, repo)
}
}
}
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index 0834a7d192..1cac613388 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -34,7 +34,8 @@ type vcsCmd struct {
scheme []string
pingCmd string
- remoteRepo func(v *vcsCmd, rootDir string) (remoteRepo string, err error)
+ remoteRepo func(v *vcsCmd, rootDir string) (remoteRepo string, err error)
+ resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error)
}
// A tagCmd describes a command to list available tags
@@ -164,8 +165,51 @@ var vcsBzr = &vcsCmd{
tagSyncCmd: "update -r {tag}",
tagSyncDefault: "update -r revno:-1",
- scheme: []string{"https", "http", "bzr", "bzr+ssh"},
- pingCmd: "info {scheme}://{repo}",
+ scheme: []string{"https", "http", "bzr", "bzr+ssh"},
+ pingCmd: "info {scheme}://{repo}",
+ remoteRepo: bzrRemoteRepo,
+ resolveRepo: bzrResolveRepo,
+}
+
+func bzrRemoteRepo(vcsBzr *vcsCmd, rootDir string) (remoteRepo string, err error) {
+ outb, err := vcsBzr.runOutput(rootDir, "config parent_location")
+ if err != nil {
+ return "", err
+ }
+ return strings.TrimSpace(string(outb)), nil
+}
+
+func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) {
+ outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo)
+ if err != nil {
+ return "", err
+ }
+ out := string(outb)
+
+ // Expect:
+ // ...
+ // (branch root|repository branch): <URL>
+ // ...
+
+ found := false
+ for _, prefix := range []string{"\n branch root: ", "\n repository branch: "} {
+ i := strings.Index(out, prefix)
+ if i >= 0 {
+ out = out[i+len(prefix):]
+ found = true
+ break
+ }
+ }
+ if !found {
+ return "", fmt.Errorf("unable to parse output of bzr info")
+ }
+
+ i := strings.Index(out, "\n")
+ if i < 0 {
+ return "", fmt.Errorf("unable to parse output of bzr info")
+ }
+ out = out[:i]
+ return strings.TrimSpace(string(out)), nil
}
// vcsSvn describes how to use Subversion.
diff --git a/src/encoding/csv/writer.go b/src/encoding/csv/writer.go
index 1faecb6648..17e7bb7f5c 100644
--- a/src/encoding/csv/writer.go
+++ b/src/encoding/csv/writer.go
@@ -115,10 +115,22 @@ func (w *Writer) WriteAll(records [][]string) (err error) {
}
// fieldNeedsQuotes returns true if our field must be enclosed in quotes.
-// Empty fields, files with a Comma, fields with a quote or newline, and
+// Fields with a Comma, fields with a quote or newline, and
// fields which start with a space must be enclosed in quotes.
+// We used to quote empty strings, but we do not anymore (as of Go 1.4).
+// The two representations should be equivalent, but Postgres distinguishes
+// quoted vs non-quoted empty string during database imports, and it has
+// an option to force the quoted behavior for non-quoted CSV but it has
+// no option to force the non-quoted behavior for quoted CSV, making
+// CSV with quoted empty strings strictly less useful.
+// Not quoting the empty string also makes this package match the behavior
+// of Microsoft Excel and Google Drive.
+// For Postgres, quote the data termating string `\.`.
func (w *Writer) fieldNeedsQuotes(field string) bool {
- if len(field) == 0 || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 {
+ if field == "" {
+ return false
+ }
+ if field == `\.` || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 {
return true
}
diff --git a/src/encoding/csv/writer_test.go b/src/encoding/csv/writer_test.go
index 22b740c074..8ddca0abe0 100644
--- a/src/encoding/csv/writer_test.go
+++ b/src/encoding/csv/writer_test.go
@@ -28,6 +28,17 @@ var writeTests = []struct {
{Input: [][]string{{"abc\ndef"}}, Output: "\"abc\r\ndef\"\r\n", UseCRLF: true},
{Input: [][]string{{"abc\rdef"}}, Output: "\"abcdef\"\r\n", UseCRLF: true},
{Input: [][]string{{"abc\rdef"}}, Output: "\"abc\rdef\"\n", UseCRLF: false},
+ {Input: [][]string{{""}}, Output: "\n"},
+ {Input: [][]string{{"", ""}}, Output: ",\n"},
+ {Input: [][]string{{"", "", ""}}, Output: ",,\n"},
+ {Input: [][]string{{"", "", "a"}}, Output: ",,a\n"},
+ {Input: [][]string{{"", "a", ""}}, Output: ",a,\n"},
+ {Input: [][]string{{"", "a", "a"}}, Output: ",a,a\n"},
+ {Input: [][]string{{"a", "", ""}}, Output: "a,,\n"},
+ {Input: [][]string{{"a", "", "a"}}, Output: "a,,a\n"},
+ {Input: [][]string{{"a", "a", ""}}, Output: "a,a,\n"},
+ {Input: [][]string{{"a", "a", "a"}}, Output: "a,a,a\n"},
+ {Input: [][]string{{`\.`}}, Output: "\"\\.\"\n"},
}
func TestWrite(t *testing.T) {
diff --git a/src/net/http/pprof/pprof.go b/src/net/http/pprof/pprof.go
index 0c7548e3ef..a23f1bc4bc 100644
--- a/src/net/http/pprof/pprof.go
+++ b/src/net/http/pprof/pprof.go
@@ -162,6 +162,10 @@ func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Unknown profile: %s\n", name)
return
}
+ gc, _ := strconv.Atoi(r.FormValue("gc"))
+ if name == "heap" && gc > 0 {
+ runtime.GC()
+ }
p.WriteTo(w, debug)
return
}
diff --git a/src/net/lookup.go b/src/net/lookup.go
index 20f20578cd..aeffe6c9b7 100644
--- a/src/net/lookup.go
+++ b/src/net/lookup.go
@@ -40,10 +40,16 @@ func lookupIPMerge(host string) (addrs []IP, err error) {
addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) {
return lookupIP(host)
})
+ return lookupIPReturn(addrsi, err, shared)
+}
+
+// lookupIPReturn turns the return values from singleflight.Do into
+// the return values from LookupIP.
+func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IP, error) {
if err != nil {
return nil, err
}
- addrs = addrsi.([]IP)
+ addrs := addrsi.([]IP)
if shared {
clone := make([]IP, len(addrs))
copy(clone, addrs)
@@ -52,41 +58,40 @@ func lookupIPMerge(host string) (addrs []IP, err error) {
return addrs, nil
}
+// lookupIPDeadline looks up a hostname with a deadline.
func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) {
if deadline.IsZero() {
return lookupIPMerge(host)
}
- // TODO(bradfitz): consider pushing the deadline down into the
- // name resolution functions. But that involves fixing it for
- // the native Go resolver, cgo, Windows, etc.
- //
- // In the meantime, just use a goroutine. Most users affected
- // by http://golang.org/issue/2631 are due to TCP connections
- // to unresponsive hosts, not DNS.
+ // We could push the deadline down into the name resolution
+ // functions. However, the most commonly used implementation
+ // calls getaddrinfo, which has no timeout.
+
timeout := deadline.Sub(time.Now())
if timeout <= 0 {
- err = errTimeout
- return
+ return nil, errTimeout
}
t := time.NewTimer(timeout)
defer t.Stop()
- type res struct {
- addrs []IP
- err error
- }
- resc := make(chan res, 1)
- go func() {
- a, err := lookupIPMerge(host)
- resc <- res{a, err}
- }()
+
+ ch := lookupGroup.DoChan(host, func() (interface{}, error) {
+ return lookupIP(host)
+ })
+
select {
case <-t.C:
- err = errTimeout
- case r := <-resc:
- addrs, err = r.addrs, r.err
+ // The DNS lookup timed out for some reason. Force
+ // future requests to start the DNS lookup again
+ // rather than waiting for the current lookup to
+ // complete. See issue 8602.
+ lookupGroup.Forget(host)
+
+ return nil, errTimeout
+
+ case r := <-ch:
+ return lookupIPReturn(r.v, r.err, r.shared)
}
- return
}
// LookupPort looks up the port for the given network and service.
diff --git a/src/net/singleflight.go b/src/net/singleflight.go
index dc58affdaa..bf599f0cc9 100644
--- a/src/net/singleflight.go
+++ b/src/net/singleflight.go
@@ -8,10 +8,18 @@ import "sync"
// call is an in-flight or completed singleflight.Do call
type call struct {
- wg sync.WaitGroup
- val interface{}
- err error
- dups int
+ wg sync.WaitGroup
+
+ // These fields are written once before the WaitGroup is done
+ // and are only read after the WaitGroup is done.
+ val interface{}
+ err error
+
+ // These fields are read and written with the singleflight
+ // mutex held before the WaitGroup is done, and are read but
+ // not written after the WaitGroup is done.
+ dups int
+ chans []chan<- singleflightResult
}
// singleflight represents a class of work and forms a namespace in
@@ -21,6 +29,14 @@ type singleflight struct {
m map[string]*call // lazily initialized
}
+// singleflightResult holds the results of Do, so they can be passed
+// on a channel.
+type singleflightResult struct {
+ v interface{}
+ err error
+ shared bool
+}
+
// Do executes and returns the results of the given function, making
// sure that only one execution is in-flight for a given key at a
// time. If a duplicate comes in, the duplicate caller waits for the
@@ -42,12 +58,52 @@ func (g *singleflight) Do(key string, fn func() (interface{}, error)) (v interfa
g.m[key] = c
g.mu.Unlock()
+ g.doCall(c, key, fn)
+ return c.val, c.err, c.dups > 0
+}
+
+// DoChan is like Do but returns a channel that will receive the
+// results when they are ready.
+func (g *singleflight) DoChan(key string, fn func() (interface{}, error)) <-chan singleflightResult {
+ ch := make(chan singleflightResult, 1)
+ g.mu.Lock()
+ if g.m == nil {
+ g.m = make(map[string]*call)
+ }
+ if c, ok := g.m[key]; ok {
+ c.dups++
+ c.chans = append(c.chans, ch)
+ g.mu.Unlock()
+ return ch
+ }
+ c := &call{chans: []chan<- singleflightResult{ch}}
+ c.wg.Add(1)
+ g.m[key] = c
+ g.mu.Unlock()
+
+ go g.doCall(c, key, fn)
+
+ return ch
+}
+
+// doCall handles the single call for a key.
+func (g *singleflight) doCall(c *call, key string, fn func() (interface{}, error)) {
c.val, c.err = fn()
c.wg.Done()
g.mu.Lock()
delete(g.m, key)
+ for _, ch := range c.chans {
+ ch <- singleflightResult{c.val, c.err, c.dups > 0}
+ }
g.mu.Unlock()
+}
- return c.val, c.err, c.dups > 0
+// Forget tells the singleflight to forget about a key. Future calls
+// to Do for this key will call the function rather than waiting for
+// an earlier call to complete.
+func (g *singleflight) Forget(key string) {
+ g.mu.Lock()
+ delete(g.m, key)
+ g.mu.Unlock()
}
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index 48d4023b9a..45d107b777 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -84,10 +84,13 @@ func symtabinit() {
}
}
- // file table follows ftab.
+ // The ftab ends with a half functab consisting only of
+ // 'entry', followed by a uint32 giving the pcln-relative
+ // offset of the file table.
sp = (*sliceStruct)(unsafe.Pointer(&filetab))
- p = unsafe.Pointer(add(unsafe.Pointer(pcln), ftab[nftab].funcoff))
- sp.array = unsafe.Pointer(add(unsafe.Pointer(pcln), ftab[nftab].funcoff))
+ end := unsafe.Pointer(&ftab[nftab].funcoff) // just beyond ftab
+ fileoffset := *(*uint32)(end)
+ sp.array = unsafe.Pointer(&pclntable[fileoffset])
// length is in first element of array.
// set len to 1 so we can get first element.
sp.len = 1
@@ -224,7 +227,7 @@ func funcline(f *_func, targetpc uintptr, file *string) int32 {
func funcspdelta(f *_func, targetpc uintptr) int32 {
x := pcvalue(f, f.pcsp, targetpc, true)
if x&(ptrSize-1) != 0 {
- print("invalid spdelta ", f.pcsp, " ", x, "\n")
+ print("invalid spdelta ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
}
return x
}
diff --git a/src/unsafe/unsafe.go b/src/unsafe/unsafe.go
index 83b2e14052..79499b2955 100644
--- a/src/unsafe/unsafe.go
+++ b/src/unsafe/unsafe.go
@@ -4,6 +4,9 @@
/*
Package unsafe contains operations that step around the type safety of Go programs.
+
+ Packages that import unsafe may be non-portable and are not protected by the
+ Go 1 compatibility guidelines.
*/
package unsafe
diff --git a/test/fixedbugs/issue8947.go b/test/fixedbugs/issue8947.go
new file mode 100644
index 0000000000..f40c02e998
--- /dev/null
+++ b/test/fixedbugs/issue8947.go
@@ -0,0 +1,53 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Some uses of zeroed constants in non-assignment
+// expressions broke with our more aggressive zeroing
+// of assignments (internal compiler errors).
+
+package main
+
+func f1() {
+ type T [2]int
+ p := T{0, 1}
+ switch p {
+ case T{0, 0}:
+ panic("wrong1")
+ case T{0, 1}:
+ // ok
+ default:
+ panic("wrong2")
+ }
+
+ if p == (T{0, 0}) {
+ panic("wrong3")
+ } else if p == (T{0, 1}) {
+ // ok
+ } else {
+ panic("wrong4")
+ }
+}
+
+type T struct {
+ V int
+}
+
+var X = T{}.V
+
+func f2() {
+ var x = T{}.V
+ if x != 0 {
+ panic("wrongx")
+ }
+ if X != 0 {
+ panic("wrongX")
+ }
+}
+
+func main() {
+ f1()
+ f2()
+}