1
0
mirror of https://github.com/golang/go synced 2024-11-22 20:04:47 -07:00

cmd/compile: Ensure left-to-right assignment

Add temporaries to reorder the assignment for OAS2XXX nodes.
This makes orderstmt(), rewrite
  a, b, c = ...
as
  tmp1, tmp2, tmp3 = ...
  a, b, c = tmp1, tmp2, tmp3
and
  a, ok = ...
as
  t1, t2 = ...
  a  = t1
  ok = t2

Fixes #13433.

Change-Id: Id0f5956e3a254d0a6f4b89b5f7b0e055b1f0e21f
Reviewed-on: https://go-review.googlesource.com/34713
Run-TryBot: Dhananjay Nakrani <dhananjayn@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Dhananjay Nakrani 2016-12-23 22:28:45 -08:00 committed by Keith Randall
parent e0d50a5830
commit 1cde87b312
2 changed files with 106 additions and 28 deletions

View File

@ -508,7 +508,7 @@ func orderstmt(n *Node, order *Order) {
orderexprlist(n.List, order)
orderexprlist(n.Rlist, order)
switch n.Op {
case OAS2, OAS2DOTTYPE:
case OAS2:
ordermapassign(n, order)
default:
order.out = append(order.out, n)
@ -554,7 +554,7 @@ func orderstmt(n *Node, order *Order) {
r.Right.Op = OARRAYBYTESTRTMP
}
ordermapkeytemp(r, order)
ordermapassign(n, order)
orderokas2(n, order)
cleantemp(t, order)
// Special: avoid copy of func call n->rlist->n.
@ -563,7 +563,7 @@ func orderstmt(n *Node, order *Order) {
orderexprlist(n.List, order)
ordercall(n.Rlist.First(), order)
ordermapassign(n, order)
orderas2(n, order)
cleantemp(t, order)
// Special: use temporary variables to hold result,
@ -574,31 +574,7 @@ func orderstmt(n *Node, order *Order) {
orderexprlist(n.List, order)
n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // i in i.(T)
var tmp1, tmp2 *Node
if !isblank(n.List.First()) {
typ := n.Rlist.First().Type
tmp1 = ordertemp(typ, order, haspointers(typ))
}
if !isblank(n.List.Second()) && !n.List.Second().Type.IsBoolean() {
tmp2 = ordertemp(Types[TBOOL], order, false)
}
order.out = append(order.out, n)
if tmp1 != nil {
r := nod(OAS, n.List.First(), tmp1)
r = typecheck(r, Etop)
ordermapassign(r, order)
n.List.SetIndex(0, tmp1)
}
if tmp2 != nil {
r := okas(n.List.Second(), tmp2)
r = typecheck(r, Etop)
ordermapassign(r, order)
n.List.SetIndex(1, tmp2)
}
orderokas2(n, order)
cleantemp(t, order)
// Special: use temporary variables to hold result,
@ -1229,3 +1205,68 @@ func okas(ok, val *Node) *Node {
}
return nod(OAS, ok, val)
}
// orderas2 orders OAS2XXXX nodes. It creates temporaries to ensure left-to-right assignment.
// The caller should order the right-hand side of the assignment before calling orderas2.
// It rewrites,
// a, b, a = ...
// as
// tmp1, tmp2, tmp3 = ...
// a, b, a = tmp1, tmp2, tmp3
// This is necessary to ensure left to right assignment order.
func orderas2(n *Node, order *Order) {
tmplist := []*Node{}
left := []*Node{}
for _, l := range n.List.Slice() {
if !isblank(l) {
tmp := ordertemp(l.Type, order, haspointers(l.Type))
tmplist = append(tmplist, tmp)
left = append(left, l)
}
}
order.out = append(order.out, n)
as := nod(OAS2, nil, nil)
as.List.Set(left)
as.Rlist.Set(tmplist)
as = typecheck(as, Etop)
orderstmt(as, order)
ti := 0
for ni, l := range n.List.Slice() {
if !isblank(l) {
n.List.SetIndex(ni, tmplist[ti])
ti++
}
}
}
// orderokas2 orders OAS2 with ok.
// Just like orderas2(), this also adds temporaries to ensure left-to-right assignment.
func orderokas2(n *Node, order *Order) {
var tmp1, tmp2 *Node
if !isblank(n.List.First()) {
typ := n.Rlist.First().Type
tmp1 = ordertemp(typ, order, haspointers(typ))
}
if !isblank(n.List.Second()) {
tmp2 = ordertemp(Types[TBOOL], order, false)
}
order.out = append(order.out, n)
if tmp1 != nil {
r := nod(OAS, n.List.First(), tmp1)
r = typecheck(r, Etop)
ordermapassign(r, order)
n.List.SetIndex(0, tmp1)
}
if tmp2 != nil {
r := okas(n.List.Second(), tmp2)
r = typecheck(r, Etop)
ordermapassign(r, order)
n.List.SetIndex(1, tmp2)
}
}

View File

@ -19,6 +19,7 @@ func main() {
p6()
p7()
p8()
p9()
}
var gx []int
@ -112,3 +113,39 @@ func p8() {
panic(m[0])
}
}
// Issue #13433: Left-to-right assignment of OAS2XXX nodes.
func p9() {
var x bool
// OAS2FUNC
x, x = fn()
checkOAS2XXX(x, "x, x = fn()")
// OAS2RECV
var c = make(chan bool, 10)
c <- false
x, x = <-c
checkOAS2XXX(x, "x, x <-c")
// OAS2MAPR
var m = map[int]bool{0: false}
x, x = m[0]
checkOAS2XXX(x, "x, x = m[0]")
// OAS2DOTTYPE
var i interface{} = false
x, x = i.(bool)
checkOAS2XXX(x, "x, x = i.(bool)")
}
//go:noinline
func fn() (bool, bool) { return false, true }
// checks the order of OAS2XXX.
func checkOAS2XXX(x bool, s string) {
if !x {
fmt.Printf("%s; got=(false); want=(true)\n", s)
panic("failed")
}
}