]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: allow composite literal structs with _ fields
authorJosh Bleecher Snyder <josharian@gmail.com>
Fri, 10 Mar 2017 06:41:32 +0000 (22:41 -0800)
committerJosh Bleecher Snyder <josharian@gmail.com>
Fri, 7 Apr 2017 22:01:18 +0000 (22:01 +0000)
Given code such as

type T struct {
  _ string
}

func f() {
  var x = T{"space"}
  // ...
}

the compiler rewrote the 'var x' line as

var x T
x._ = "space"

The compiler then rejected the assignment to
a blank field, thus rejecting valid code.

It also failed to catch a number of invalid assignments.
And there were insufficient checks for validity
when emitting static data, leading to ICEs.

To fix, check earlier for explicit blanks field names,
explicitly handle legit blanks in sinit,
and don't try to emit static data for nodes
for which typechecking has failed.

Fixes #19482

Change-Id: I594476171d15e6e8ecc6a1749e3859157fe2c929
Reviewed-on: https://go-review.googlesource.com/38006
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/gc/sinit.go
src/cmd/compile/internal/gc/typecheck.go
src/cmd/internal/obj/data.go
test/fixedbugs/issue19482.go [new file with mode: 0644]

index 47aee51c17b9c09e68402262f40c967207994428..0ff94abe2e86c6150506d6190b8a5f2288eb095c 100644 (file)
@@ -725,6 +725,9 @@ func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes)
                        if r.Op != OSTRUCTKEY {
                                Fatalf("fixedlit: rhs not OSTRUCTKEY: %v", r)
                        }
+                       if isblanksym(r.Sym) {
+                               return nblank, r.Left
+                       }
                        return nodSym(ODOT, var_, r.Sym), r.Left
                }
        default:
@@ -1346,8 +1349,12 @@ func isvaluelit(n *Node) bool {
 }
 
 func genAsStatic(as *Node) {
+       if as.Left.Type == nil {
+               Fatalf("genAsStatic as.Left not typechecked")
+       }
+
        var nam Node
-       if !stataddr(&nam, as.Left) || nam.Class != PEXTERN {
+       if !stataddr(&nam, as.Left) || (nam.Class != PEXTERN && as.Left != nblank) {
                Fatalf("genAsStatic: lhs %v", as.Left)
        }
 
index b272d27612f60c4fca6810c8bac9de77f422d55b..db4ea0a8954d7bff86f04fa02dc0dc366d39c1a7 100644 (file)
@@ -3100,7 +3100,7 @@ func typecheckcomplit(n *Node) *Node {
                                        // the field to the right of the dot,
                                        // so s will be non-nil, but an OXDOT
                                        // is never a valid struct literal key.
-                                       if key.Sym == nil || key.Op == OXDOT {
+                                       if key.Sym == nil || key.Op == OXDOT || isblanksym(key.Sym) {
                                                yyerror("invalid field name %v in struct initializer", key)
                                                l.Left = typecheck(l.Left, Erv)
                                                continue
index 114841dedb471f607858647766d1c4c8a9f19df9..5f583071e62047dcb86636f84315e57e5a2eb3ab 100644 (file)
@@ -70,7 +70,7 @@ func (s *LSym) GrowCap(c int64) {
 // prepwrite prepares to write data of size siz into s at offset off.
 func (s *LSym) prepwrite(ctxt *Link, off int64, siz int) {
        if off < 0 || siz < 0 || off >= 1<<30 {
-               log.Fatalf("prepwrite: bad off=%d siz=%d s=%v", off, siz, s)
+               ctxt.Diag("prepwrite: bad off=%d siz=%d s=%v", off, siz, s)
        }
        if s.Type == SBSS || s.Type == STLSBSS {
                ctxt.Diag("cannot supply data for BSS var")
diff --git a/test/fixedbugs/issue19482.go b/test/fixedbugs/issue19482.go
new file mode 100644 (file)
index 0000000..97497a4
--- /dev/null
@@ -0,0 +1,34 @@
+// 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.
+
+// Compiler rejected initialization of structs to composite literals
+// in a non-static setting (e.g. in a function)
+// when the struct contained a field named _.
+
+package p
+
+type T struct {
+       _ string
+}
+
+func ok() {
+       var x = T{"check"}
+       _ = x
+       _ = T{"et"}
+}
+
+var (
+       y = T{"stare"}
+       w = T{_: "look"} // ERROR "invalid field name _ in struct initializer"
+       _ = T{"page"}
+       _ = T{_: "out"} // ERROR "invalid field name _ in struct initializer"
+)
+
+func bad() {
+       var z = T{_: "verse"} // ERROR "invalid field name _ in struct initializer"
+       _ = z
+       _ = T{_: "itinerary"} // ERROR "invalid field name _ in struct initializer"
+}