Commit 92bb694a authored by Ian Lance Taylor's avatar Ian Lance Taylor Committed by Brad Fitzpatrick

cmd/compile: s.f aliases itself

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: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: 's avatarMatthew Dempsky <mdempsky@google.com>
parent 1bf779a4
......@@ -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.
......
// 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)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment