Go version
go version go1.26.5 darwin/arm64
golang.org/x/tools master at a5c4651b8e4951086fc536519d0eb869feefa7cb.
What did you do?
I built and interpreted this program with cmd/ssadump from the latest
x/tools master:
package main
var (
c = make(chan int, 1)
x int
order [2]int
n int
)
func fc() chan int {
order[n] = 1
n++
return c
}
func fp() *int {
order[n] = 100
n++
return &x
}
func main() {
c <- 1
select {
case *fp() = <-fc():
}
println(order[0], order[1])
}
$ go run .
1 100
$ go run golang.org/x/tools/cmd/ssadump@master -build=C -run .
100 1
The relevant SSA is:
t0 = fp()
t1 = fc()
t2 = <-t1
*t0 = t2
What did you expect to see?
The SSA interpreter should print 1 100, and the SSA should evaluate fc,
perform the receive, and only then evaluate fp.
The select statement rules say that receive-assignment left-hand-side
expressions are not evaluated when entering the select. They are evaluated
only after a communication is selected and the receive is performed:
https://go.dev/ref/spec#Select_statements
What did you see instead?
The single-case optimization in builder.selectStmt lowers the communication
as an ordinary assignment statement. Ordinary assignment lowering evaluates
the LHS before the RHS, so fp runs before fc and the receive. This changes
observable side effects.
The general multi-case select lowering does not have this particular ordering
problem because it evaluates the channel and performs the select before
building the receive-assignment LHS.
Downstream context
LLGo currently repairs the generated SSA after construction. The downstream
workaround and regression tests are in:
xgo-dev/llgo#1805
Go version
go version go1.26.5 darwin/arm64golang.org/x/toolsmaster ata5c4651b8e4951086fc536519d0eb869feefa7cb.What did you do?
I built and interpreted this program with
cmd/ssadumpfrom the latestx/tools master:
The relevant SSA is:
What did you expect to see?
The SSA interpreter should print
1 100, and the SSA should evaluatefc,perform the receive, and only then evaluate
fp.The select statement rules say that receive-assignment left-hand-side
expressions are not evaluated when entering the select. They are evaluated
only after a communication is selected and the receive is performed:
https://go.dev/ref/spec#Select_statements
What did you see instead?
The single-case optimization in
builder.selectStmtlowers the communicationas an ordinary assignment statement. Ordinary assignment lowering evaluates
the LHS before the RHS, so
fpruns beforefcand the receive. This changesobservable side effects.
The general multi-case select lowering does not have this particular ordering
problem because it evaluates the channel and performs the select before
building the receive-assignment LHS.
Downstream context
LLGo currently repairs the generated SSA after construction. The downstream
workaround and regression tests are in:
xgo-dev/llgo#1805