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>
diff --git a/misc/cgo/test/test.go b/misc/cgo/test/test.go
index 8c69ad9..35bc3a1 100644
--- a/misc/cgo/test/test.go
+++ b/misc/cgo/test/test.go
@@ -901,6 +901,12 @@
 // 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 @@
 // 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 6c22147..4064f0a 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -123,7 +123,9 @@
 		// 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, "= ")
 		}