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/cgo: const identifier is non-constant in Go code #19816

Closed
efournival opened this issue Apr 1, 2017 · 7 comments
Closed

cmd/cgo: const identifier is non-constant in Go code #19816

efournival opened this issue Apr 1, 2017 · 7 comments
Labels
FrozenDueToAge NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.

Comments

@efournival
Copy link

efournival commented Apr 1, 2017

What did you do?

package main

// #define CONST1 10
// const int CONST2 = sizeof(double);
import "C"

type (
	//Array [C.CONST1]byte
	Array [C.CONST2]byte
)

func main() {
	var a Array
	a[0] = 0
}

What did you expect to see?

go build terminating without error, which is the case when I use the first definition (commented here) of Array

What did you see instead?

./main.go:9: non-constant array bound *_Cvar_CONST2

System details

go version go1.8 linux/amd64
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/edgar/ownCloud/go"
GORACE=""
GOROOT="/usr/lib/go"
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build246141425=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
GOROOT/bin/go version: go version go1.8 linux/amd64
GOROOT/bin/go tool compile -V: compile version go1.8 X:framepointer
uname -sr: Linux 4.10.5-1-ARCH
LSB Version:	1.4
Distributor ID:	Arch
Description:	Arch Linux
Release:	rolling
Codename:	n/a
/usr/lib/libc.so.6: GNU C Library (GNU libc) stable release version 2.25, by Roland McGrath et al.
@ghost
Copy link

ghost commented Apr 2, 2017

This is correct behaviour. C does not allow a const int as the size of an array or in switch statements.

@efournival
Copy link
Author

Indeed, I'm currently working on C++ code with only a C binding.
For example, the following code will compile under g++ but not with gcc:

const int SIZE = sizeof(double);
typedef int Array[SIZE];

int main(int argc, char *argv[])
{
	Array array;
	array[0] = 0;
	return 0;
}

However, the following Go code will compile and run just fine :

package main

import "unsafe"

const SIZE = unsafe.Sizeof(float64(0))

type Array [SIZE]byte

func main() {
	var a Array
	a[0] = 0
}

Then, I just do not understand why the code I put in my first post will not compile. I can turn this bug report into a proposal if this is "working as intended" in Go.

@bradfitz
Copy link
Contributor

bradfitz commented Apr 2, 2017

I don't think @ianlancetaylor intends for cgo to support C++, but I'll let him decide.

@bradfitz bradfitz added the NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. label Apr 2, 2017
@bcmills
Copy link
Contributor

bcmills commented Apr 2, 2017

It would be nice if cgo could treat C declarations of the form

const T x = y

as equivalent to Go statements of the form

const x C.T = y

for types C.T that are valid as Go constants.

That seems more-or-less independent of the C++ support for the same usage.

@efournival
Copy link
Author

@bcmills totally got my point. C++ support for cgo would be nice but I think this is another debate.

However, fixing (if it's a bug) or implementing (if it's a proposal, as it's not completely clear yet) const T x = y (C) <=> const x C.T = y (Go) into cgo shouldn't be too difficult. I think one just has to interpret #define and const the same way. I would be interested to do it if you guys find this useful.

@ianlancetaylor
Copy link
Contributor

ianlancetaylor commented Apr 3, 2017

I don't think this is a good idea. The corresponding C code

const int CONST2 = sizeof(double);
int a[CONST2];

does not compile. Treating a C const int as a Go const would be an odd special case. In C a const int is an immutable variable. It's not a constant in the Go sense. It is not the same as a C++ const int, which is much more similar to the Go meaning of const.

For the reason, it's also hard to implement. The cgo tool tries to figure out what kind of name it is given by generating C code and looking at the errors it gets. Specifically it will generate code like

const int CONST2 = sizeof(double);
#line 1 "not-declared"
void __cgo_f_1_1(void) { __typeof__(CONST2) *__cgo_undefined__; }
#line 1 "not-type"
void __cgo_f_1_2(void) { CONST2 *__cgo_undefined__; }
#line 1 "not-const"
void __cgo_f_1_3(void) { enum { __cgo__undefined__ = (CONST2)*1 }; }

An error in __cgo_f_1_1 means that CONST2 is not declared at all. An error in __cgo_f_1_2 means that CONST2 is not a type. An error in __cgo_f_1_3 means that CONST2 is not an integer constant. Compiling this code will give an error for __cgo_f_1_2 and __cgo_f_1_3, so cgo will conclude that CONST2 is not a type and is not a constant. You want cgo to recognize CONST2 as a constant, but in C it is not. So we would need to special case it somehow.

It would be possible in principle to special case it. The debug info for CONST2 will have DW_TAG_const_type attached to the underlying type, int.

Once we've detected that it is immutable, we would have to determine the value, since a Go constant can not refer to the C value. cgo normally determines the value of a constant by generating code like

long long __cgodebug_data[] = {
	CONST2
};

and then examining the value of the variable. But that again does not work in C (it does in C++), so again we would need to special case determining the value.

So it's special cases at every level. It doesn't seem worth doing to me. Sorry.

@efournival
Copy link
Author

When you don't know how cgo works internally, it sounded quite simple to do. I was wrong. Thanks for your explanation!

I'm working on a corner case implying Go <=> C <=> C++ which leaded to this const mess. Fortunately this is not blocking (for me at least) nor affecting a lot of people.

Have a nice day.

@golang golang locked and limited conversation to collaborators Apr 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.
Projects
None yet
Development

No branches or pull requests

5 participants