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: internal compiler error compiling a rune literal #29350

Closed
robohack opened this issue Dec 20, 2018 · 6 comments
Closed

cmd/compile: internal compiler error compiling a rune literal #29350

robohack opened this issue Dec 20, 2018 · 6 comments
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@robohack
Copy link

What version of Go are you using (go version)?

Both of these:

$ go version
go version go1.11.2 darwin/amd64
$ go version
go version go1.11.1 netbsd/amd64

(and play.golang.org)

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/gaw/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/gaw/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/Cellar/go/1.11.2/libexec"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.11.2/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/jw/rz51m7zd15g6dn5km5xxmk7w0000gn/T/go-build982594623=/tmp/go-build -gno-record-gcc-switches -fno-common"
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/more/woods/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="netbsd"
GOOS="netbsd"
GOPATH="/home/more/woods/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/pkg/go111"
GOTMPDIR=""
GOTOOLDIR="/usr/pkg/go111/pkg/tool/netbsd_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build870652082=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I have a silly little test for a silly little function I use, and it has a var pre-initialized with some literals, and one day I decided to copy this test to another package, and suddenly it would not compile.

Here it is alone in its own program, also failing to compile.

And here's a playground with it: https://play.golang.org/p/ksGkIh7cVod

// a weird compiler error

package main

import (
	"fmt"
)

// ITE() -- perhaps the best equivalent to C's "c?a:b" ternary operator
//
func ITE(condition bool, a interface{}, b interface{}) interface{} {
	if condition {
		return a
	}
	return b
}

type comparableStruct struct {
	boo  bool
	foo  int
	bar  float32
	none complex64
	name string
}

var ITETests = []struct {
	ifTrue  interface{}
	ifFalse interface{}
}{
	{
		ifTrue:  true,
		ifFalse: false},
	{
		ifTrue:  "true",
		ifFalse: "false"},
	{
		ifTrue:  1,
		ifFalse: 0},
	{
		ifTrue:  0.1,
		ifFalse: 0.0},
	{
		ifTrue:  1.e+1,
		ifFalse: 1.e+0},
	{
		ifTrue:  1.e+1i,
		ifFalse: 1.e+0i},
	{
		ifTrue:  '⊨',  // char appears in file as 0xe2 0x8a 0xa8
		ifFalse: '⊭'}, // char appears in file as 0xe2 0x8a 0xad
	{
		ifTrue:  comparableStruct{true, 1, 1.0, 1.0i, "true"},
		ifFalse: comparableStruct{false, 0, 0.0, 0.0i, "false"}}}

func TestITE() {
	for _, res := range ITETests {
		var out interface{}

		fmt.Printf("Testing %q,%q\n", res.ifTrue, res.ifFalse)
		out = ITE(true, res.ifTrue, res.ifFalse)
		if out != res.ifTrue {
			fmt.Printf("expected %q, got %q\n", res.ifTrue, out)
		}
		out = ITE(false, res.ifTrue, res.ifFalse)
		if out != res.ifFalse {
			fmt.Printf("expected %q, got %q\n", res.ifFalse, out)
		}
	}
}

func main() {
	TestITE()
}

What did you expect to see?

This is copied from the one _test.go file where I first wrote it and where it compiles and runs just fine. The relevant bytes in this test's source file are identical, and there is no BOM on either file. I can't see anything relevant that's different between the files where it works and where it fails, other than the fact that the one where it works is larger and has other vars and functions.

=== RUN   TestITE
Testing %!q(bool=true),%!q(bool=false)
Testing "true","false"
Testing '\x01','\x00'
Testing %!q(float64=0.1),%!q(float64=0)
Testing %!q(float64=10),%!q(float64=1)
Testing %!q(complex128=(0+10i)),%!q(complex128=(0+1i))
Testing '⊨','⊭'
Testing {%!q(bool=true) '\x01' %!q(float32=1) %!q(complex64=(0+1i)) "true"},{%!q(bool=false) '\x00' %!q(float32=0) %!q(complex64=(0+0i)) "false"}
--- PASS: TestITE (0.15s)

What did you see instead?

go build tite2.go
# command-line-arguments
./tite2.go:49:3: prepwrite: bad off=0 siz=-1000000000 s="".statictmp_13
./tite2.go:49:3: WriteInt: bad integer size: -1000000000
./tite2.go:50:3: prepwrite: bad off=0 siz=-1000000000 s="".statictmp_14
./tite2.go:50:3: WriteInt: bad integer size: -1000000000

This may be a "new" bug as it does compile and run fine with 1.10:

$ go build tite2.go
$ ./tite2
Testing %!q(bool=true),%!q(bool=false)
Testing "true","false"
Testing '\x01','\x00'
Testing %!q(float64=0.1),%!q(float64=0)
Testing %!q(float64=10),%!q(float64=1)
Testing %!q(complex128=(0+10i)),%!q(complex128=(0+1i))
Testing '⊨','⊭'
Testing {%!q(bool=true) '\x01' %!q(float32=1) %!q(complex64=(0+1i)) "true"},{%!q(bool=false) '\x00' %!q(float32=0) %!q(complex64=(0+0i)) "false"}
$ go version
go version go1.10 linux/amd64
@robohack robohack changed the title a very odd error compiling a literal, but not an error in the original source, or on older system a very odd error compiling a rune literal, but not an error in the original source, or on older system Dec 20, 2018
@agnivade
Copy link
Contributor

Interestingly, if you add var x = '⊨' as a global variable, the error disappears.

@josharian
Copy link
Contributor

Congrats, you found a compiler bug! From the error message looks like there’s a missing dowidth call. This should bisect nicely if anyone is up for it. Since it exists in 1.11 this isn’t a release blocker for 1.12, although I’m tentatively marking for 1.12 milestone because I suspect the fix will be simple, localized, and safe.

@josharian josharian changed the title a very odd error compiling a rune literal, but not an error in the original source, or on older system cmd/compile: internal compiler error compiling a rune literal Dec 20, 2018
@agnivade
Copy link
Contributor

Some more oddities -

This compiles with 1.10.3, but not with 1.11.2 or 1.12beta1

package main

import "fmt"

var ITETests = []struct {
	ifTrue  interface{}
	ifFalse interface{}
}{
	{
		ifTrue:  '⊨',  // char appears in file as 0xe2 0x8a 0xa8
		ifFalse: '⊭'}, // char appears in file as 0xe2 0x8a 0xad
}

func TestITE() {
	for _, res := range ITETests {
		fmt.Printf("expected %q\n", res.ifFalse)
	}
}

But, this does not with 1.10.3, 1.11.2 and 1.12beta1 -

package main

var ITETests = []struct {
	ifTrue  interface{}
	ifFalse interface{}
}{
	{
		ifTrue:  '⊨',  // char appears in file as 0xe2 0x8a 0xa8
		ifFalse: '⊭'}, // char appears in file as 0xe2 0x8a 0xad
}
$go tool compile jsonerr.go 
jsonerr.go:8:3: prepwrite: bad off=0 siz=-1000000000 s="".statictmp_1
jsonerr.go:8:3: WriteInt: bad integer size: -1000000000
jsonerr.go:9:3: prepwrite: bad off=0 siz=-1000000000 s="".statictmp_2
jsonerr.go:9:3: WriteInt: bad integer size: -1000000000

@josharian josharian added this to the Go1.12 milestone Dec 20, 2018
@josharian josharian added the NeedsFix The path to resolution is known, but the work has not been done. label Dec 20, 2018
@unfunco
Copy link

unfunco commented Dec 20, 2018

The issue is activated by the indexed export format being made the default in commit a3c75d9, but the issue is introduced in commit ca2f85f, when the indexed export format feature is merged.

@mdempsky mdempsky self-assigned this Dec 20, 2018
@mdempsky
Copy link
Contributor

mdempsky commented Dec 20, 2018

Minimal repro:

$ cat x.go
package p

var X interface{} = 'x'

$ go tool compile x.go
x.go:3:5: prepwrite: bad off=0 siz=-1000000000 s="".statictmp_0
x.go:3:5: WriteInt: bad integer size: -1000000000

Seems to be due to the implicit conversion. Changing 'x' to rune('x') (which should be equivalent) works okay.

@gopherbot
Copy link
Contributor

Change https://golang.org/cl/155380 mentions this issue: cmd/compile: fix ICE due to bad rune width

@golang golang locked and limited conversation to collaborators Dec 20, 2019
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

6 participants