https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121212
Bug ID: 121212 Summary: Two enumerated types without enumerator lists shouldn't be compatible Product: gcc Version: 16.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: luigighiron at gmail dot com Target Milestone: --- The following program demonstrates why two enumerated types without enumerator lists shouldn't be compatible (in the same translation unit), as GCC allows them to be if they have the same tag: enum E:int; typedef enum E A; int main(){ enum E:int; typedef enum E B; extern A x; extern B x; enum E:int{h}; A*p=&x; B*q=&x; } First, an enumerated type called E with no enumerator list is declared at file scope and aliased with the name A. Second, in the scope of main another enumerated type called E with no enumerator list is declared and aliased with the name B. Both enumerated types have an underlying type of int. Third, x is declared twice with external linkage using the types A and B. Fourth, the enumerated type E in main is redeclared to give it an enumerator list. Lastly, two pointers to x of types A* and B* are declared. After the two declarations of x, it has the composite type of A and B which is some enumerated type which is compatible with both types. But after the redeclaration which gives the enumerated type E in main an enumerator list, A and B are no longer compatible and there is no type which is compatible with both A and B. Hence, the composite type can't be compatible with both types which violates the definition of a composite type. GCC currently just chooses the first enumerated type as the composite type, so the declaration of p is accepted while q is rejected. Though not explicitly spelled out in the standard, I think that the intent here is that this code should be invalid, just like how this program is invalid: struct S; typedef struct S A; int main(){ struct S; typedef struct S B; extern A x; extern B x; } The lack of an enumerator list should prevent that type from being compatible with another enumerated type in the same translation unit, just like how a structure type lacking a definition prevents it from being compatible with another structure type in the same translation unit. Because GCC allows two enumerated types without enumerator lists to be compatible, it creates strange scenarios like the first program which later add enumerator lists to make the types incompatible. Another example is: enum E:int; typedef enum E A; A x=0; int main(){ enum E:int; typedef enum E B; B*p=&x; B b=*p; enum E:int{h}; } A and B are compatible at the point of *p, so maybe it is defined for that reason. Alternatively, maybe it is undefined because A and B later become incompatible and the access is done at runtime so it should consider that. Clang currently accepts the first program because it allows an enumerated type without an enumerator list to be compatible with any enumerated type with the same tag and underlying type, regardless of the whether it has an enumerator list. I don't think this is any more correct than what GCC currently does, and the same issue can be recreated by giving the file scope enumerated type an incompatible enumerator list.