https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79658
--- Comment #4 from Pedro Alves <palves at redhat dot com> --- Here's a better one: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ template <typename E> struct enum_flags { enum_flags &operator|= (E e) { m_enum_value = (E) (m_enum_value | e); return *this; } operator E () const { return m_enum_value; } E m_enum_value; }; enum flag { FLAG1 = 1, }; typedef enum_flags<flag> eflags; extern void bar (); void foo_0 (int param) { eflags f0; if (param) f0 |= FLAG1; if (f0 != 0) // doesn't warn bar (); } void foo_1 (int param) { eflags f1; if (param) f1 |= FLAG1; if (f1 != FLAG1) // warns bar (); } void foo_2 (int param) { eflags f2; if (param) f2 |= FLAG1; if (f2 != 1) // doesn't warn bar (); } void foo_3 (int param) { eflags f3; if (param) f3 |= FLAG1; if (f3 != 3) // warns bar (); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We get: $ /opt/gcc/bin/g++ -std=gnu++11 enum_flags2.cc -o enum_flags.o -g3 -O2 -Wuninitialized -c -Wall -Wextra enum_flags2.cc: In function ‘void foo_1(int)’: enum_flags2.cc:6:25: warning: ‘f1’ may be used uninitialized in this function [-Wmaybe-uninitialized] m_enum_value = (E) (m_enum_value | e); ^~~~~~~~~~~~ enum_flags2.cc:40:10: note: ‘f1’ was declared here eflags f1; ^~ enum_flags2.cc: In function ‘void foo_3(int)’: enum_flags2.cc:6:25: warning: ‘f3’ may be used uninitialized in this function [-Wmaybe-uninitialized] m_enum_value = (E) (m_enum_value | e); ^~~~~~~~~~~~ enum_flags2.cc:64:10: note: ‘f3’ was declared here eflags f3; ^~ In particular, note that the uses in foo_0 and foo_2 did NOT warn while the uses in foo_1 and foo_3 did warn. Why's that? The use I was originally most interested in catching was the one like in foo_0, where we compare against 0. The original code has means to make comparing enum_flags against other integer literals fail to compile. (0 means bit flags not set, the code is implementing a type-safe enum flags wrapper). I just tried the other values for completeness, thinking that maybe 0 was being given "special" treatment, though foo_2 seems to show otherwise. FWIW, adding enum values to cover all the compared-to values makes no difference: enum flag { FLAG0 = 0, FLAG1 = 1, FLAG2 = 2, FLAG3 = 3, }; Same set of warnings.