]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: Ensure left-to-right assignment
authorDhananjay Nakrani <dhananjaynakrani@gmail.com>
Sat, 24 Dec 2016 06:28:45 +0000 (22:28 -0800)
committerKeith Randall <khr@golang.org>
Sat, 11 Feb 2017 21:46:21 +0000 (21:46 +0000)
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>
src/cmd/compile/internal/gc/order.go
test/reorder.go

index 9530d4d928d575cc09a5121447c8c52e242b34dd..2a707a32accf65bfa3fb7954adaa54768850d214 100644 (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)
+       }
+}
index fc44be90de7ca5d37d0de24fd36dc0e8d9108db9..3a87d025c2a955383601aa46520f65fd7b446705 100644 (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")
+       }
+}