Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile: string range loop does not handle assigment order correctly #18376

Closed
martisch opened this issue Dec 19, 2016 · 7 comments
Closed
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@martisch
Copy link
Contributor

martisch commented Dec 19, 2016

at least go 1.7.4 (playground) and tip

https://play.golang.org/p/CG--RNbwZA

x := []rune{'a', 'b'}
i := 1
for i, x[i] = range "c" {
   break
}

expected:
x[0] = 'a'
x[1] = 'c'

got:
x[0] = 'c'
x[1] = 'b'

I have already created a fix for this issue. Currently testing if we could make it not regress performance for the common case (e.g. i,x := ) without adding to much additional complexity to the compiler code.

Note that this bug seems not to have been introduced with the new string range code but already existed in at least 1.7.4 . However the new string range code in 1.8 does not handle this case correctly either.

@cespare
Copy link
Contributor

cespare commented Dec 19, 2016

It took me a bit to see what's wrong with the behavior. In case it helps anyone else looking at this, the specific issue is that spec says

The assignment proceeds in two phases. First, the operands of index expressions and pointer indirections (including implicit pointer indirections in selectors) on the left and the expressions on the right are all evaluated in the usual order. Second, the assignments are carried out in left-to-right order.

(link).

Below that it also gives this example for an []int, which works today (unlike strings, which this issue is about):

i = 2
x = []int{3, 5, 7}
for i, x[i] = range x {  // set i, x[2] = 0, x[0]
	break
}
// after this loop, i == 0 and x == []int{3, 5, 3}

@bradfitz
Copy link
Contributor

@bradfitz bradfitz added this to the Go1.9 milestone Dec 19, 2016
@ianlancetaylor
Copy link
Contributor

I agree that this looks like a bug in the gc compiler.

gccgo gets it right.

I also agree with setting the milestone for this to 1.9.

@quentinmit quentinmit added the NeedsFix The path to resolution is known, but the work has not been done. label Dec 20, 2016
@martisch
Copy link
Contributor Author

Since the fix will be for 1.9 i will take a little more time for tuning the performance of the fix before submitting a CL.

@alandonovan
Copy link
Contributor

We should add this test case to $GOROOT/test/range.go, analogous to what testslice already does for slices:

diff --git a/test/range.go b/test/range.go
index bae7a1c..b4b181b 100644
--- a/test/range.go
+++ b/test/range.go
@@ -311,6 +311,19 @@ func teststring2() {
        }
 }
 
+// Regression test for Go issue #18376.
+func teststring3() {
+       x := []rune{'a', 'b'}
+       i := 1
+       for i, x[i] = range "c" {
+               break
+       }
+       if i != 0 || x[0] != 'a' || x[1] != 'c' {
+               println("wrong parallel assignment", i, string(x[0]), string(x[1]))
+               panic("fail")
+       }
+}
+
 // test that range over map only evaluates
 // the expression after "range" once.
 
@@ -420,6 +433,7 @@ func main() {
        teststring()
        teststring1()
        teststring2()
+       teststring3()
        testmap()
        testmap1()
        testmap2()

FWIW, golang.org/x/tools/go/ssa also does the right thing.

@martisch
Copy link
Contributor Author

martisch commented Dec 21, 2016

@alandonovan sure, that what i did to verify the bug too (and then copied to the playground link) and will be in the CL. However i put the test into teststring function similar to testslice.

@gopherbot
Copy link

CL https://golang.org/cl/35955 mentions this issue.

@golang golang locked and limited conversation to collaborators Feb 28, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

7 participants