]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix select statement evaluation order corner case
authorMatthew Dempsky <mdempsky@google.com>
Thu, 10 Dec 2020 20:21:45 +0000 (12:21 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Fri, 11 Dec 2020 22:02:02 +0000 (22:02 +0000)
The Go spec requires that select case clauses be evaluated in order,
which is stricter than normal ordering semantics. cmd/compile handled
this correctly for send clauses, but was not correctly handling
receive clauses that involved bare variable references.

Discovered with @cuonglm.

Fixes #43111.

Change-Id: Iec93b6514dd771875b084ba49c15d7f4531b4a6f
Reviewed-on: https://go-review.googlesource.com/c/go/+/277132
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/gc/order.go
test/fixedbugs/issue43111.go [new file with mode: 0644]

index 863de5b6c71b49ddc32e65e9b4bb29c90e029922..30e1535c09c43a516e00d7ad864ec56f25abf34a 100644 (file)
@@ -891,7 +891,7 @@ func (o *Order) stmt(n *Node) {
                                // c is always evaluated; x and ok are only evaluated when assigned.
                                r.Right.Left = o.expr(r.Right.Left, nil)
 
-                               if r.Right.Left.Op != ONAME {
+                               if !r.Right.Left.IsAutoTmp() {
                                        r.Right.Left = o.copyExpr(r.Right.Left, r.Right.Left.Type, false)
                                }
 
diff --git a/test/fixedbugs/issue43111.go b/test/fixedbugs/issue43111.go
new file mode 100644 (file)
index 0000000..76d7beb
--- /dev/null
@@ -0,0 +1,70 @@
+// run
+
+// Copyright 2020 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.
+
+package main
+
+var ch chan int
+var x int
+
+func f() int {
+       close(ch)
+       ch = nil
+       return 0
+}
+
+func g() int {
+       ch = nil
+       x = 0
+       return 0
+}
+
+func main() {
+       var nilch chan int
+       var v int
+       var ok bool
+       _, _ = v, ok
+
+       ch = make(chan int)
+       select {
+       case <-ch:
+       case nilch <- f():
+       }
+
+       ch = make(chan int)
+       select {
+       case v = <-ch:
+       case nilch <- f():
+       }
+
+       ch = make(chan int)
+       select {
+       case v := <-ch: _ = v
+       case nilch <- f():
+       }
+
+       ch = make(chan int)
+       select {
+       case v, ok = <-ch:
+       case nilch <- f():
+       }
+
+       ch = make(chan int)
+       select {
+       case v, ok := <-ch: _, _ = v, ok
+       case nilch <- f():
+       }
+
+       ch1 := make(chan int, 1)
+       ch = ch1
+       x = 42
+       select {
+       case ch <- x:
+       case nilch <- g():
+       }
+       if got := <-ch1; got != 42 {
+               panic(got)
+       }
+}