diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 0185a0f9f4..911e0a4dd5 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -1326,8 +1326,12 @@ ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init) lr->n = safeexpr(lr->n, init); nn = nil; - for(ll=nl, lr=nr; ll && lr; ll=ll->next, lr=lr->next) + for(ll=nl, lr=nr; ll && lr; ll=ll->next, lr=lr->next) { + // Do not generate 'x = x' during return. See issue 4014. + if(op == ORETURN && ll->n == lr->n) + continue; nn = list(nn, ascompatee1(op, ll->n, lr->n, init)); + } // cannot happen: caller checked that lists had same length if(ll || lr) diff --git a/src/pkg/runtime/race/testdata/regression_test.go b/src/pkg/runtime/race/testdata/regression_test.go index c48f7b8600..066ccbb38e 100644 --- a/src/pkg/runtime/race/testdata/regression_test.go +++ b/src/pkg/runtime/race/testdata/regression_test.go @@ -127,3 +127,21 @@ func divInSlice() { i := 1 _ = v[(i*4)/3] } + +func TestNoRaceReturn(t *testing.T) { + c := make(chan int) + noRaceReturn(c) + <-c +} + +// Return used to do an implicit a = a, causing a read/write race +// with the goroutine. Compiler has an optimization to avoid that now. +// See issue 4014. +func noRaceReturn(c chan int) (a, b int) { + a = 42 + go func() { + _ = a + c <- 1 + }() + return a, 10 +}