diff options
author | Matthew Dempsky <mdempsky@google.com> | 2020-07-30 18:35:00 -0700 |
---|---|---|
committer | Matthew Dempsky <mdempsky@google.com> | 2020-07-31 16:35:33 +0000 |
commit | 7388956b76ce15a11346cebefcf6193db044caaf (patch) | |
tree | c87a48b8fc6e61ab26c5a8dba5f2f04bca0e8342 | |
parent | b56791cdea5caa87ffcd585d29c294bd3d08a06a (diff) | |
download | go-7388956b76ce15a11346cebefcf6193db044caaf.tar.gz go-7388956b76ce15a11346cebefcf6193db044caaf.zip |
cmd/cgo: fix mangling of enum and union types
Consider this test package:
package p
// enum E { E0 };
// union U { long x; };
// void f(enum E e, union U* up) {}
import "C"
func f() {
C.f(C.enum_E(C.E0), (*C.union_U)(nil))
}
In Go 1.14, cgo translated this to (omitting irrelevant details):
type _Ctype_union_U [8]byte
func f() {
_Cfunc_f(uint32(_Ciconst_E0), (*[8]byte)(nil))
}
func _Cfunc_f(p0 uint32, p1 *[8]byte) (r1 _Ctype_void) { ... }
Notably, _Ctype_union_U was declared as a defined type, but uses were
being rewritten into uses of the underlying type, which matched how
_Cfunc_f was declared.
After CL 230037, cgo started consistently rewriting "C.foo" type
expressions as "_Ctype_foo", which caused it to start emitting:
type _Ctype_enum_E uint32
type _Ctype_union_U [8]byte
func f() {
_Cfunc_f(_Ctype_enum_E(_Ciconst_E0), (*_Ctype_union_U)(nil))
}
// _Cfunc_f unchanged
Of course, this fails to type-check because _Ctype_enum_E and
_Ctype_union_U are defined types.
This CL changes cgo to emit:
type _Ctype_enum_E = uint32
type _Ctype_union_U = [8]byte
// f unchanged since CL 230037
// _Cfunc_f still unchanged
It would probably be better to fix this in (*typeConv).loadType so
that cgo generated code uses the _Ctype_foo aliases too. But as it
wouldn't have any effect on actual compilation, it's not worth the
risk of touching it at this point in the release cycle.
Updates #39537.
Fixes #40494.
Change-Id: I88269660b40aeda80a9a9433777601a781b48ac0
Reviewed-on: https://go-review.googlesource.com/c/go/+/246057
Reviewed-by: Ian Lance Taylor <iant@golang.org>
-rw-r--r-- | misc/cgo/test/test.go | 13 | ||||
-rw-r--r-- | src/cmd/cgo/out.go | 4 |
2 files changed, 16 insertions, 1 deletions
diff --git a/misc/cgo/test/test.go b/misc/cgo/test/test.go index 8c69ad91ac..35bc3a1447 100644 --- a/misc/cgo/test/test.go +++ b/misc/cgo/test/test.go @@ -901,6 +901,12 @@ typedef struct S32579 { unsigned char data[1]; } S32579; // issue 38649 // Test that #define'd type aliases work. #define netbsd_gid unsigned int + +// issue 40494 +// Inconsistent handling of tagged enum and union types. +enum Enum40494 { X_40494 }; +union Union40494 { int x; }; +void issue40494(enum Enum40494 e, union Union40494* up) {} */ import "C" @@ -2204,3 +2210,10 @@ var issue38649 C.netbsd_gid = 42 // issue 39877 var issue39877 *C.void = nil + +// issue 40494 +// No runtime test; just make sure it compiles. + +func Issue40494() { + C.issue40494(C.enum_Enum40494(C.X_40494), (*C.union_Union40494)(nil)) +} diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 6c221473e0..4064f0ae41 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -123,7 +123,9 @@ func (p *Package) writeDefs() { // Moreover, empty file name makes compile emit no source debug info at all. var buf bytes.Buffer noSourceConf.Fprint(&buf, fset, def.Go) - if bytes.HasPrefix(buf.Bytes(), []byte("_Ctype_")) { + if bytes.HasPrefix(buf.Bytes(), []byte("_Ctype_")) || + strings.HasPrefix(name, "_Ctype_enum_") || + strings.HasPrefix(name, "_Ctype_union_") { // This typedef is of the form `typedef a b` and should be an alias. fmt.Fprintf(fgo2, "= ") } |