]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: s.f aliases itself
authorIan Lance Taylor <iant@golang.org>
Thu, 31 Mar 2016 20:58:33 +0000 (13:58 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Fri, 1 Apr 2016 00:47:56 +0000 (00:47 +0000)
The change in 20907 fixed varexpr but broke aliased.  After that change,
a reference to a field in a struct would not be seen as aliasing itself.
Before that change, it would, but only because all fields in a struct
aliased everything.

This CL changes the compiler to consider all references to a field as
aliasing all other fields in that struct.  This is imperfect--a
reference to one field does not alias another field--but is a simple fix
for the immediate problem.  A better fix would require tracking the
specific fields as well.

Fixes #15042.

Change-Id: I5c95c0dd7b0699e53022fce9bae2e8f50d6d1d04
Reviewed-on: https://go-review.googlesource.com/21390
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/gc/walk.go
test/fixedbugs/issue15042.go [new file with mode: 0644]

index bab9c003002f660f9255d66c0da1124093cafb19..a3e8a044d009a68ecc2703b595775cba707581b8 100644 (file)
@@ -2335,6 +2335,12 @@ func aliased(n *Node, all []*Node, i int) bool {
                return false
        }
 
+       // Treat all fields of a struct as referring to the whole struct.
+       // We could do better but we would have to keep track of the fields.
+       for n.Op == ODOT {
+               n = n.Left
+       }
+
        // Look for obvious aliasing: a variable being assigned
        // during the all list and appearing in n.
        // Also record whether there are any writes to main memory.
@@ -2346,6 +2352,11 @@ func aliased(n *Node, all []*Node, i int) bool {
        var a *Node
        for _, an := range all[:i] {
                a = outervalue(an.Left)
+
+               for a.Op == ODOT {
+                       a = a.Left
+               }
+
                if a.Op != ONAME {
                        memwrite = 1
                        continue
@@ -2436,7 +2447,8 @@ func varexpr(n *Node) bool {
                return varexpr(n.Left) && varexpr(n.Right)
 
        case ODOT: // but not ODOTPTR
-               return varexpr(n.Left)
+               // Should have been handled in aliased.
+               Fatalf("varexpr unexpected ODOT")
        }
 
        // Be conservative.
diff --git a/test/fixedbugs/issue15042.go b/test/fixedbugs/issue15042.go
new file mode 100644 (file)
index 0000000..71b0712
--- /dev/null
@@ -0,0 +1,27 @@
+// run
+
+// Copyright 2016 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.
+
+// Exchanging two struct fields was compiled incorrectly.
+
+package main
+
+type S struct {
+       i int
+}
+
+func F(c bool, s1, s2 S) (int, int) {
+       if c {
+               s1.i, s2.i = s2.i, s1.i
+       }
+       return s1.i, s2.i
+}
+
+func main() {
+       i, j := F(true, S{1}, S{20})
+       if i != 20 || j != 1 {
+               panic(i+j)
+       }
+}