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

Comments

Projects
None yet
6 participants
@robohack
Copy link

commented Dec 20, 2018

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

This comment has been minimized.

Copy link
Member

commented Dec 20, 2018

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

@josharian

This comment has been minimized.

Copy link
Contributor

commented Dec 20, 2018

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

This comment has been minimized.

Copy link
Member

commented Dec 20, 2018

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 label Dec 20, 2018

@unfunco

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link

commented Dec 20, 2018

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

@gopherbot gopherbot closed this in 706b54b Dec 20, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.