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>
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.
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
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.
--- /dev/null
+// 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)
+ }
+}