Skip to content

Commit c944639

Browse files
committed
cmd/compile: allow composite literal structs with _ fields
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 <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 44a0681 commit c944639

File tree

4 files changed

+44
-3
lines changed

4 files changed

+44
-3
lines changed

src/cmd/compile/internal/gc/sinit.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,9 @@ func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes)
725725
if r.Op != OSTRUCTKEY {
726726
Fatalf("fixedlit: rhs not OSTRUCTKEY: %v", r)
727727
}
728+
if isblanksym(r.Sym) {
729+
return nblank, r.Left
730+
}
728731
return nodSym(ODOT, var_, r.Sym), r.Left
729732
}
730733
default:
@@ -1346,8 +1349,12 @@ func isvaluelit(n *Node) bool {
13461349
}
13471350

13481351
func genAsStatic(as *Node) {
1352+
if as.Left.Type == nil {
1353+
Fatalf("genAsStatic as.Left not typechecked")
1354+
}
1355+
13491356
var nam Node
1350-
if !stataddr(&nam, as.Left) || nam.Class != PEXTERN {
1357+
if !stataddr(&nam, as.Left) || (nam.Class != PEXTERN && as.Left != nblank) {
13511358
Fatalf("genAsStatic: lhs %v", as.Left)
13521359
}
13531360

src/cmd/compile/internal/gc/typecheck.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3100,7 +3100,7 @@ func typecheckcomplit(n *Node) *Node {
31003100
// the field to the right of the dot,
31013101
// so s will be non-nil, but an OXDOT
31023102
// is never a valid struct literal key.
3103-
if key.Sym == nil || key.Op == OXDOT {
3103+
if key.Sym == nil || key.Op == OXDOT || isblanksym(key.Sym) {
31043104
yyerror("invalid field name %v in struct initializer", key)
31053105
l.Left = typecheck(l.Left, Erv)
31063106
continue

src/cmd/internal/obj/data.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func (s *LSym) GrowCap(c int64) {
7070
// prepwrite prepares to write data of size siz into s at offset off.
7171
func (s *LSym) prepwrite(ctxt *Link, off int64, siz int) {
7272
if off < 0 || siz < 0 || off >= 1<<30 {
73-
log.Fatalf("prepwrite: bad off=%d siz=%d s=%v", off, siz, s)
73+
ctxt.Diag("prepwrite: bad off=%d siz=%d s=%v", off, siz, s)
7474
}
7575
if s.Type == SBSS || s.Type == STLSBSS {
7676
ctxt.Diag("cannot supply data for BSS var")

test/fixedbugs/issue19482.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// errorcheck
2+
3+
// Copyright 2017 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
// Compiler rejected initialization of structs to composite literals
8+
// in a non-static setting (e.g. in a function)
9+
// when the struct contained a field named _.
10+
11+
package p
12+
13+
type T struct {
14+
_ string
15+
}
16+
17+
func ok() {
18+
var x = T{"check"}
19+
_ = x
20+
_ = T{"et"}
21+
}
22+
23+
var (
24+
y = T{"stare"}
25+
w = T{_: "look"} // ERROR "invalid field name _ in struct initializer"
26+
_ = T{"page"}
27+
_ = T{_: "out"} // ERROR "invalid field name _ in struct initializer"
28+
)
29+
30+
func bad() {
31+
var z = T{_: "verse"} // ERROR "invalid field name _ in struct initializer"
32+
_ = z
33+
_ = T{_: "itinerary"} // ERROR "invalid field name _ in struct initializer"
34+
}

0 commit comments

Comments
 (0)