tinygo-org / tinygo

Go compiler for small places. Microcontrollers, WebAssembly (WASM/WASI), and command-line tools. Based on LLVM.
https://tinygo.org
Other
15.16k stars 890 forks source link

multiple assignment statements executed in the wrong order #3963

Open dgryski opened 10 months ago

dgryski commented 10 months ago

Via @ydnar

package main

/*
This program demonstrates a difference in behavior between Go and TinyGo.
In Go, the multiple assignment is evaluated after the call to toUpper.
In TinyGo, the assignment happens prior to the call to toUpper.

See: https://go.dev/ref/spec#Assignment_statements

$ go run ./cmd/tinygo-assign-bug
HELLO HELLO <nil>

$ tinygo run ./cmd/tinygo-assign-bug
HELLO hello <nil>
*/

import (
    "fmt"
    "strings"
)

func main() {
    s1 := "hello"
    s2, err := s1, toUpper(&s1)
    fmt.Println(s1, s2, err)
}

func toUpper(s *string) error {
    *s = strings.ToUpper(*s)
    return nil
}
aykevl commented 10 months ago

Huh, that's interesting.

I'd have to investigate, but I expect this to be a bug in the golang.org/x/tools/go/ssa package.

dgryski commented 10 months ago

I agree. Here is a dump of the SSA code generated for main:

func main():
0:                                                                entry P:0 S:0
    t0 = new string (s1)                                            *string
    *t0 = "hello":string
    t1 = *t0                                                         string
    t2 = toUpper(t0)                                                  error
    t3 = *t0                                                         string
    t4 = println(t3, t1, t2)                                             ()
    return

And TinyGo is doing a faithful translation of those instructions.

ydnar commented 10 months ago

@dgryski the output of ssadump looks different than what I saw. What was the command you used to produce this?

ydnar commented 10 months ago

This might already be known: https://github.com/golang/go/issues/48105

dgryski commented 10 months ago

So this is undefined behaviour in Go. The compiler does one this. The SSA package (and this tinygo) and gccgo take a different interpretation.