Go: Cannot use `func` as a field name in a C struct.

Created on 14 Oct 2020  路  3Comments  路  Source: golang/go

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

$ go version
go version go1.14.2 linux/amd64

Does this issue reproduce with the latest release?

Will try later when I have access to a machine with gvm

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

go env Output

$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
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-build918375297=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I am adding CUDA 11 support for the CUDA library. This means using cgo. One of the structs is defined as follows:

typedef struct CUDA_KERNEL_NODE_PARAMS_st {
    CUfunction func;
    unsigned int gridDimX;
    unsigned int gridDimY;
    unsigned int gridDimZ;
    unsigned int blockDimX;
    unsigned int blockDimY;
    unsigned int blockDimZ;
    unsigned int sharedMemBytes;
    void** kernelParams;
    void** extra;
} CUDA_KERNEL_NODE_PARAMS;

This struct needs to be passed into a function call.

I am unable to set the field .func. I have tried with a literal:

return C.CUDA_KERNEL_NODE_PARAMS {
        func: p.Func.fn,
        gridDimX: p.GridDimX,
        gridDimY: p.GridDimY,
        gridDimZ: p.GridDimZ,
        blockDimX: p.BlockDimX,
        blockDimY: p.BlockDimY,
        blockDimZ: p.BlockDimZ,
        sharedMemBytes: p.SharedMemBytes,
    }

I have tried it as a selector:

retVal := C.CUDA_KERNEL_NODE_PARAMS {
        gridDimX: p.GridDimX,
        gridDimY: p.GridDimY,
        gridDimZ: p.GridDimZ,
        blockDimX: p.BlockDimX,
        blockDimY: p.BlockDimY,
        blockDimZ: p.BlockDimZ,
        sharedMemBytes: p.SharedMemBytes,
    }
retVal.func = p.Func.fn

What did you expect to see?

No parsing errors

What did you see instead?

For the first case I got:

 expected '(', found ':'

For the second case I got:

./params.go:28:9: expected selector or type assertion, found 'func'

Look, I understand that this is a parsing error. I also understand that Go's goal is to have a one-pass parser. Having to check if we're in a C.XXX context will make it two passes. I have no suggestions.

Workaround

Right now I have a terrible workaround: the struct creation is a cgo function that I call, passing in all the correct values. This is not ideal clearly. The whole point of using CUDA is to speed up computation, and if I have to call cgo repeatedly then that's not great. Especially in this case, where the compiler's just allocating a data structure and populating with values.

Most helpful comment

go doc cmd/cgo says:

Go references to C

Within the Go file, C's struct field names that are keywords in Go can be
accessed by prefixing them with an underscore: if x points at a C struct
with a field named "type", x._type accesses the field.

So in this case the field can be referred to as _func, not func.

There is no need to "look into the whole func-as-a-keyword thing".

All 3 comments

@noxer suggested another workaround that I hadn't thought of: anonymous struct fields:

return C.CUDA_KERNEL_NODE_PARAMS {
        p.Func.fn,
        p.GridDimX,
        p.GridDimY,
        p.GridDimZ,
        p.BlockDimX,
        p.BlockDimY,
        p.BlockDimZ,
        p.SharedMemBytes,
        nil,
        nil,
    }

It's a nice workaround that does what I had originally intended. But maybe we should look into the whole func-as-a-keyword thing?

go doc cmd/cgo says:

Go references to C

Within the Go file, C's struct field names that are keywords in Go can be
accessed by prefixing them with an underscore: if x points at a C struct
with a field named "type", x._type accesses the field.

So in this case the field can be referred to as _func, not func.

There is no need to "look into the whole func-as-a-keyword thing".

Hah serves me right for not RTFMing

Was this page helpful?
0 / 5 - 0 ratings