From 92bb694a493723d901a253bc88be53a207c8d550 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 31 Mar 2016 13:58:33 -0700 Subject: [PATCH] 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 TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/walk.go | 14 +++++++++++++- test/fixedbugs/issue15042.go | 27 +++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue15042.go diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index bab9c00300..a3e8a044d0 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -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 index 0000000000..71b0712d56 --- /dev/null +++ b/test/fixedbugs/issue15042.go @@ -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) + } +} -- 2.48.1