25

I need to use scoped enums so that I can pass them as specific types to our serialiser. I have given explicit integer values for the enum members of Enum1.

I have put two scoped enums matching the description above into a bitfield thus

enum class Enum1 {
    value1 = 0x0,
    value2 = 0x1,
    value3 = 0x2
};
enum class Enum2 {
    value1 = 0x0,
    value2,
    value3,
 // ...
    value14
};

struct Example {
    Enum1 value1 : 2;
    Enum2 value2 : 6;
}

Now wherever I use the Example type, I get the warning "'Example::value1' is too small to hold all values of 'Enum1'", and similarly for Enum2. Note that this is not the case for the values we have defined and we are not concerned at all with values outside of these.

This is quite a serious distraction in our build process - the project is large and complex and we don't want to have to scan through many of these warnings (and there are many).

I had a look for a GCC (G++) flag to disable the specific warning. Is there one that I can pass on the command line? Ideally, I would use the warning pragma to disable it locally, if possible.

There is little scope for changing the code structure at this point, but we could really use these spurious warnings removed.

Edit: Added scoped enums with identifiers changed.

Cœur
  • 37,241
  • 25
  • 195
  • 267
jsren
  • 325
  • 3
  • 7
  • 1
    if Enum1 contains values more than 3, then it will not fit on 2 bits – nikniknik2016 Mar 15 '16 at 07:39
  • Can you show the definition of `Enum1` and `Enum2`? – Angew is no longer proud of SO Mar 15 '16 at 08:01
  • @nikniknik2016: It doesn't – jsren Mar 15 '16 at 09:40
  • @Angew: Nope, company code, sorry! – jsren Mar 15 '16 at 09:41
  • 3
    @jsren Then create an articial [mcve] reproducing the same issue, and post that. We cannot help with code we cannot see. – Angew is no longer proud of SO Mar 15 '16 at 09:49
  • @Angew I will, thank you. I was hoping for a compiler flag, as a general-case solution. Hence the lack of example. – jsren Mar 16 '16 at 08:13
  • 1
    While I can't figure out the status of it, there's this [gcc bug report](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51242) – nos Mar 16 '16 at 08:27
  • @nos: While this bug opened as a compiler error about scoped enums and bitfields (now fixed), it is kept opened because they didn't figure out the best way to disable the warning. The last post is about 2 years ago, so they probably just forgot about it. – rodrigo Mar 16 '16 at 08:39
  • Lol, this code causes Internal Compiler Error in MSVC 2017 (I accidentally had godbolt set to that from last time) – M.M May 14 '18 at 22:26
  • The range of a 2-bit ssigned bitfield is `[-2, 1]`. The value `0x2` is actually out of range for `Enum1::value1`. (And it is confusing that `Example` has the same field name as the enumerator values it stores) – M.M May 14 '18 at 22:28
  • I am facing the same problem and this warning seems to be completely pointless and vexing. Following the same logic, the compiler should've warned me that `i` is too small to hold all values of `int` when I write something like `int i : 10;` – Egor Nov 03 '18 at 18:49
  • Similar question: [Is this warning related to enum class size wrong?](https://stackoverflow.com/q/22606392/427158) – maxschlepzig Aug 27 '22 at 14:18

4 Answers4

17

The problem is that an scoped enum always has an integral underlying type. By default, it is int but you can change it to any other integral type, such as unsigned char.

Unfortunately you cannot change the underlying type to a bit-field, as they are not real C++ types.

You could try disabling the warning, but a quick skim through the G++ code reveals these lines (gcc/cp/class.c:3468):

  else if (TREE_CODE (type) == ENUMERAL_TYPE
           && (0 > (compare_tree_int
                    (w, TYPE_PRECISION (ENUM_UNDERLYING_TYPE (type))))))
    warning_at (DECL_SOURCE_LOCATION (field), 0,
                "%qD is too small to hold all values of %q#T",
                field, type);

The key here is the call to warning_at(...) instead of warning(OPT_to_disable_the_warning, ...). So currently there is no option to disable it. Except recompiling the compiler yourself!

For what it is worth CLang++-3.7.1 does not warn about it.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • Cheers. Tbh I think it's a useful warning. If it had a better description. And really only the first time. My major issue with it is the fact that it occurs _multiple times_ for both each field and for each compilation unit. Despite using only one g++ invocation. What's the best way of prodding the devs about this? – jsren Mar 16 '16 at 09:19
3

As I recall, an enum with a declared underlying type can hold any value of that type, regardless of what enumeration constants are defined. Since you can say

val= enum2{148}

and expect it to work properly, the warning seems correct for that case. You are not declaring a base type, and historically this means that the enum is only guaranteed to be big enough to hold the range of values given by the lowest through highest enumeration constant. So I would expect no warning here. Maybe the new enum class also expects a full range even though the underlying type was automatically determined (or the compiler thinks it does)? You might try using a pure old-syntax enum and see if that works any differently.

JDługosz
  • 5,592
  • 3
  • 24
  • 45
  • 4
    The enums in the question don't have a declared underlying type. But actually the rule is that if there is *fixed underlying type* then any value of the underlying type is a valid enumerator value. And scoped enums (i.e. `enum class`) always have a fixed underlying type, which is `int` if not otherwise specified – M.M May 14 '18 at 22:33
0

Emitting this warning is a bug, because all declared enumerator (values) in fact can be held by the bitfield fields.

Like with traditional enums, a variable of scoped enum type still can hold any value of its underlying type, even ones that don't correspond to a declared enumerator.

However, warning about this like this

warning: 'some bitfield field' is too small to hold all values of 'enum class FOO'

is quite pointless because assigning a too large value as in

Example x;
x.value1 = Enum1(8);

already generates a -Woverflow warning.


Consequently, GCC fixed this warning in version 9.3.

FWIW, Clang never warned about.


IOW, to suppress this warning in GCC you have to upgrade to GCC version 9.3 or later.

maxschlepzig
  • 35,645
  • 14
  • 145
  • 182
-1

For other people like me who end up here from search:

This problem only applies to C++11 scoped enums. If you need bitfield enums, old style enums without explicit storage size work fine:

enum Enum1 {
    Enum1_value1 = 0x0,
    Enum1_value2 = 0x1,
    Enum1_value3 = 0x2
};
enum Enum2 {
    Enum2_value1 = 0x0,
    Enum2_value2,
    Enum2_value3,
 // ...
    Enum2_value14
};

struct Example {
    Enum1 value1 : 2;
    Enum2 value2 : 6;
}
jpa
  • 10,351
  • 1
  • 28
  • 45
  • It also applies to underlying-type-fixed **unscoped** enums such as `enum Enum1 : uint8_t`, when comping with GCC < 9.3. – maxschlepzig Aug 27 '22 at 13:55