https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81665
Bug ID: 81665 Summary: Please introduce flags attribute for enums which will mimic one from C# Product: gcc Version: 5.4.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: bugzi...@poradnik-webmastera.com Target Milestone: --- Enums usually are used to define set of strongly-typed constants, and every enum element is considered separate from others (assuming that their values are different too). However sometimes they are also used as flags, which can be or'ed together. This causes numerous problems: - when two values are or'ed together and used as a label in switch, this triggers compilation warning: test-enum-op.c: In function ‘int main()’: test-enum-op.c:25:5: warning: case value ‘6’ not in enumerated type ‘Values’ [-Wswitch] case Val2 | Val3: ^ - in C++ mode two enum values can be or'ed together, but resulting value will have int type. This causes error when it is then assigned to variable of enum type: test-enum-op.c:19:23: error: invalid conversion from ‘int’ to ‘Values’ [-fpermissive] Values v = Val1 | Val2; ^ - to eliminate above error, one has to define custom | operator for enum type. However when it is not marked as a constexpr, it causes another compilation error when its result is used as a case value: test-enum-op.c:25:15: error: call to non-constexpr function ‘Values operator|(Values, Values)’ case Val2 | Val3: ^ - I also recall some tautological compare warning, that comparison is always true or false. However I was not able to write code to demonstrate this here, so maybe it was from clang. It would be good to introduce __attribute__((flags)) which could be used with enums. It should work in similar way as a [Flags] attribute in C#. It would help to address issues listed above. Tested on gcc 4.8.5 (Redhat 7) and 5.4.0 (Cygwin). Code: typedef enum Values { Val_None = 0, Val1 = 1, Val2 = 2, Val3 = 4, } Values; #ifdef __cplusplus constexpr Values operator|(Values a, Values b) { return static_cast<Values>(static_cast<unsigned>(a) | static_cast<unsigned>(b)); } #endif int main() { Values v = Val1 | Val2; switch(v) { case Val1: return 1; case Val2 | Val3: return 3; default: break; } if (v == -1) return 6; return 0; }