Search code examples
c++enumsgcc-warningenum-class

Is GCC correct to warn of format string mismatch with a scoped enum?


When using a scoped enum in a varargs context, it is defined to be passed as its underlying type, as answered in "Can I use enum class values as arguments to varargs functions?" As I understand it, this is the only circumstance in which a scoped enum will be converted implicitly, like an unscoped enum is.

Consider this program:

enum Foo : char { F };
enum class Bar : char { B };

#include <cstdio>
int main()
{
    return !std::printf("%c\n", Foo::F)
        +  !std::printf("%c\n", Bar::B);
}

The compiler (g++ version 6.3.0) is happy with the first print, of a Foo, but complains when I pass a Bar:

0.cpp: In function ‘int main()’:
0.cpp:10:34: warning: format ‘%c’ expects argument of type ‘int’, but argument 2 has type ‘Bar’ [-Wformat=]
         +  !printf("%c\n", Bar::B);
                                  ^

g++ version 4.8.2 didn't complain about this, but g++ 6.3.0 does (and that's why it now concerns me). Both versions complain about the first print when there is a substantive mismatch, such as using %f or %s, or if I change Foo to use a long underlying type; that's why I enable -Wformat.

I understand that warnings are not a standards-conformance issue, and I know how to change my code to address these (e.g. using the functions in answers to How can I output the value of an enum class in C++11?), but I also believe that warnings are unhelpful if they produce false positives. Is there any potential for actual harm in passing a scoped enum to a formatted I/O function when the underlying type of the enum matches the corresponding conversion specification in the format string?


Solution

  • From this scoped enumeration reference:

    There are no implicit conversions from the values of a scoped enumerator to integral types, ...

    [Emphasis mine]

    That means no matter the base type, a scoped enumeration will not be implicitly converted to an int (or any other integer type). You must explicitly do the conversion, with e.g. static_cast (continued from previous quote):

    ... although static_cast may be used to obtain the numeric value of the enumerator.


    Also, from this variadic argument reference:

    bool, char, short, and unscoped enumerations are converted to int or wider integer types as in integer promotion

    [Again emphasis mine]


    And to answer your question if GCC is right in warning you: Yes it is right. What you're doing is not correct.