Bug 51242 - [C++11] Unable to use strongly typed enums as bit fields
Summary: [C++11] Unable to use strongly typed enums as bit fields
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.6.1
: P3 normal
Target Milestone: 9.2
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2011-11-20 18:41 UTC by Vladimir
Modified: 2022-02-12 03:11 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2012-11-18 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vladimir 2011-11-20 18:41:15 UTC
In case of use strongly typed enumS as bit fields of structS in C++0x mode, compiler says "bit-field 'smth' with non-integral type".

Though, the standard says "A bit-field shall have integral or enumeration type (3.9.1)."
Comment 1 Jonathan Wakely 2011-11-20 20:26:58 UTC
In future please provide a complete testcase, as requested at http://gcc.gnu.org/bugs

Testcase reduced from the one you posted to the gcc-help list:

enum class MyEnum { A = 1 };

struct MyClass
{
  MyEnum Field1 : 3;
};


Jason, the standard seems to say this should work, although I am rather surprised - is that intended?
Comment 2 Vladimir 2012-11-19 05:47:19 UTC
What does 'rejects-valid' keywords mean?
18.11.2012 22:05 пользователь "redi at gcc dot gnu.org" <
gcc-bugzilla@gcc.gnu.org> написал:

>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51242
>
> Jonathan Wakely <redi at gcc dot gnu.org> changed:
>
>            What    |Removed                     |Added
>
> ----------------------------------------------------------------------------
>              Status|UNCONFIRMED                 |NEW
>    Last reconfirmed|                            |2012-11-18
>      Ever Confirmed|0                           |1
>
> --
> Configure bugmail: http://gcc.gnu.org/bugzilla/userprefs.cgi?tab=email
> ------- You are receiving this mail because: -------
> You reported the bug.
>
Comment 3 Daniel Krügler 2012-11-19 07:26:11 UTC
(In reply to comment #2)
> What does 'rejects-valid' keywords mean?
It means that the compiler rejects valid code, see

http://gcc.gnu.org/bugzilla/describekeywords.cgi
Comment 4 Vladimir 2012-11-19 07:56:26 UTC
Sorry for stupid questions :)

Is this bug planned to be fixed in future?

Can I help in any way to do that?

2012/11/19 daniel.kruegler at googlemail dot com <gcc-bugzilla@gcc.gnu.org>:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51242
>
> --- Comment #3 from Daniel Krügler <daniel.kruegler at googlemail dot com> 2012-11-19 07:26:11 UTC ---
> (In reply to comment #2)
>> What does 'rejects-valid' keywords mean?
> It means that the compiler rejects valid code, see
>
> http://gcc.gnu.org/bugzilla/describekeywords.cgi
>
> --
> Configure bugmail: http://gcc.gnu.org/bugzilla/userprefs.cgi?tab=email
> ------- You are receiving this mail because: -------
> You reported the bug.
Comment 5 Jonathan Wakely 2012-11-19 11:47:20 UTC
(In reply to comment #4)
> Is this bug planned to be fixed in future?

Yes, of course. It's a bug.

> Can I help in any way to do that?

Sure, you could look in gcc/cp/*.c for the message
  "bit-field .* with non-integral type"
and see what conditions it depends on and why it disallows scoped enumeration types.
Comment 6 Jonathan Wakely 2012-11-19 11:52:38 UTC
The check is for an unscoped enumeration type which does seem intentional.

This change allows the example to compile:

--- cp/decl2.c.orig     2012-11-19 11:50:28.842443803 +0000
+++ cp/decl2.c  2012-11-19 11:46:08.445472115 +0000
@@ -1026,7 +1026,7 @@
   if (TREE_CODE (value) == VOID_TYPE)
     return void_type_node;

-  if (!INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (value))
+  if (!INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (value))
       && (POINTER_TYPE_P (value)
           || !dependent_type_p (TREE_TYPE (value))))
     {

It emits a warning though:

e.cc:5:19: warning: 'MyClass::Field1' is too small to hold all values of 'enum class MyEnum' [enabled by default]
Comment 7 Vladimir 2012-11-19 16:31:15 UTC
OK, I will see this message soon.

P.S. For now, I have to use Intel Compiller, which isn't good due limited platform support (x86 and amd64).
---Исходное сообщение---
От: "redi at gcc dot gnu.org"
Отпр.:  19.11.2012, 15:47 
Кому: volodya@netfolder.ru
Тема: [Bug c++/51242] [C++11] Unable to use strongly typed enums as bit fields



http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51242

--- Comment #5 from Jonathan Wakely <redi at gcc dot gnu.org> 2012-11-19 11:47:20 UTC ---
(In reply to comment #4)
> Is this bug planned to be fixed in future?

Yes, of course. It's a bug.

> Can I help in any way to do that?

Sure, you could look in gcc/cp/*.c for the message
  "bit-field .* with non-integral type"
and see what conditions it depends on and why it disallows scoped enumeration
types.
Comment 8 Paolo Carlini 2012-11-26 11:26:16 UTC
The warning noticed by Jon seems a latent issue unrelated to bitfields and due to the fact to for scoped enums, the underlying type, if not explicitly specified is if fixed to int type. Thus, in finish_enum_value_list, fixed_underlying_type_p is true and the code "restricting" ENUM_UNDERLYING_TYPE for the benefit of diagnostics doesn't run. It seems that it should run anyway, when the underlying type is fixed but implicitly so.
Comment 9 Paolo Carlini 2012-11-26 11:32:15 UTC
Or maybe it should *always* run, if the point is diagnostics: after all even if the type is fixed why not adding to its representation the information about the actual range of values of the enumerators?!?
Comment 10 Paolo Carlini 2012-11-26 11:36:56 UTC
For example, consider this variant of the PR53661 situation:

enum class Code {
  SUCCESS = 0
};

Code a;

short r[] = {a};

we currently produce a -Wnarrowing warning, which seems bogus to me, exactly because we don't realize that actually the only enumerator has value zero.
Comment 11 Jonathan Wakely 2012-11-26 11:46:46 UTC
That narrowing warning seems right to me, the enum variable could have a value out of range of short:

  Code a = static_cast<Code>(SHRT_MAX+1);
Comment 12 Jonathan Wakely 2012-11-26 11:50:43 UTC
The difference from PR 53661 is that the underlying type of a scoped enumeration is fixed, so its values are the values of (in this case) int. In PR 53661 the underlying type is not fixed.
Comment 13 Paolo Carlini 2012-11-26 12:00:17 UTC
But something still seems wrong to me. Why warning depending on whether 'class' is there for the following:

enum /*class*/ Code {
  SUCCESS = 0
};

Code a;

short r[] = {a};
Comment 14 Paolo Carlini 2012-11-26 12:05:21 UTC
Anyway, the latent issue is of course with fixed underlying types: if in that case we don't care about warning more, this issue is already fixed, very likely. Even better ;)
Comment 15 Paolo Carlini 2012-11-26 12:12:12 UTC
To be clear, for:

enum class Code {
  SUCCESS = 0
};

Code a;// = static_cast<Code>(SHRT_MAX+1);

short r[] = {a};

we *error* out anyway, isn't that we are only emitting a warning and only when we are assigning the SHRT_MAX + 1.
Comment 16 Paolo Carlini 2012-11-26 12:22:49 UTC
And to further clarify wrt your specific Comment 11, Jon, for:

#include <limits.h>

enum Code {
  SUCCESS = 0
};

Code a = static_cast<Code>(SHRT_MAX + 1);

short r[] = {a};

we currently don't warn.
Comment 17 Jonathan Wakely 2012-11-26 12:43:37 UTC
(In reply to comment #15)
> we *error* out anyway, isn't that we are only emitting a warning and only when
> we are assigning the SHRT_MAX + 1.

But isn't the error because there's no implicit conversion from a scoped enunmeration type to short?  That's just invalid.

And my point is that the narrowing warning is correct, because 'a' is not a constant expression and its value could be out of the range [SHRT_MIN,SHRT_MAX].

(In reply to comment #16)
> And to further clarify wrt your specific Comment 11, Jon, for:
> 
> #include <limits.h>
> 
> enum Code {
>   SUCCESS = 0
> };
> 
> Code a = static_cast<Code>(SHRT_MAX + 1);
> 
> short r[] = {a};
> 
> we currently don't warn.

Because the values of that unscoped enum type are [0,1] which always fit in short.  With a scoped enumeration type the underlying type is fixed so the values of the enumeration type are the values of the underlying type which are [INT_MIN,INT_MAX].  But this seems unrelated to using scoped enums as bitfields anyway.
Comment 18 Paolo Carlini 2012-11-26 12:50:15 UTC
What can I say, if we are happy with these warnings when the underlying type is fixed, then I think your patch is all there is to this issue, just regression test it ;) It would be nice to double check that clang also warns, tough.
Comment 19 Jonathan Wakely 2012-11-26 12:56:34 UTC
Clang doesn't warn for the code in comment 1
Comment 20 Paolo Carlini 2012-11-26 13:00:08 UTC
Well, then we should double check whether it warns at all when bitfields are not involved, because I don't see anything bitfield-specific about the warning. Maybe it just warns less for these narrowing issues with scoped and unscoped enums?
Comment 21 Paolo Carlini 2012-11-26 13:27:45 UTC
Uhm, actually, when the underlying type is unscoped and we already accept the code, we warn exactly in the same way. I'm not sure if this is already clear to everybody, definitely wasn't clear to me, sorry if I misled you Jon or somebody else into thinking that the possible issues having to do with -Wnarrowing were important for this issue, I understand now they are not:

enum MyEnum { A1 = 1, A2 = 2 };

struct MyClass
{
  MyEnum Field1 : 1;
};

Thus, it really seems the fix for this issue boils down to loosening the check in grokbitfield and that's it.
Comment 22 Paolo Carlini 2012-11-26 13:39:17 UTC
I mean, with the grokbitfield tweak we obtain a behavior for Comment #1 which in terms of warnings it's just a variant of Comment #13: if we already decided that it's fine to warn when the underlying type is fixed for Comment #13, we have in my opinion to consistently warn for Comment #1.
Comment 23 Paolo Carlini 2012-11-26 14:00:37 UTC
Patchlet in Comment #6 passes testing for me.

As I tried clumsily to explain, I don't think it's consistent to avoid the warning for Comment #1 if we warn for Comment #13 scoped, but it's also annoying that the "too small to hold all values" warning it's enable by default, thus can't be suppresed: maybe we could give it a name (if we don't want to re-open the discussion about -Wnarrowing and the range of the underlying type when the type is fixed ;)
Comment 24 Jonathan Wakely 2012-11-26 14:40:20 UTC
I think naming the warning would make sense, so it can be disabled by people who want to use scoped enums with bit-fields
Comment 25 paolo@gcc.gnu.org 2013-02-16 01:07:16 UTC
Author: paolo
Date: Sat Feb 16 01:07:11 2013
New Revision: 196100

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=196100
Log:
/cp
2013-02-15  Jonathan Wakely  <jwakely.gcc@gmail.com>
	    Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/51242
	* decl2.c (grokbitfield): Allow scoped enumeration types.

/testsuite
2013-02-15  Jonathan Wakely  <jwakely.gcc@gmail.com>
	    Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/51242
	* g++.dg/cpp0x/enum23.C: New.


Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/enum23.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/decl2.c
    trunk/gcc/testsuite/ChangeLog
Comment 26 Paolo Carlini 2013-02-27 10:32:49 UTC
Note: I'm keeping this open because we may want to do something about the warning:

  http://gcc.gnu.org/ml/gcc-patches/2013-02/msg00786.html
Comment 27 Tom Honermann 2016-06-14 18:20:15 UTC
We got bit by this warning recently.  We compile with -Werror and, without an option to suppress warnings in the following code, gcc rejects it.  We think this code should be accepted without a warning given the constant expressions involved.

Clang does not issue a warning for this code.  However, if an assignment to the bit-field from a literal '2' (cast to E) is added, then Clang warns on the assignment itself (as opposed to on the bit-field declaration).  This seems like a more useful approach.

$ cat t.cpp
enum E : unsigned char {
    e0 = 0,
    e1 = 1
};
struct S {
    E e : 1;
};
void f(S s) {
    s.e = e0;
    s.e = e1;
    s.e = (E)0;
    s.e = (E)1;
};

$ g++ --version
g++ (GCC) 6.1.1 20160531
...

$ g++ -c -std=c++11 -Werror t.cpp
t.cpp:6:11: error: ‘S::e’ is too small to hold all values of ‘enum E’ [-Werror]
     E e : 1;
           ^
cc1plus: all warnings being treated as errors
Comment 28 Sasha B 2016-09-20 00:55:37 UTC
I contribute to Chromium and have also hit problems such as Comment 27. I'm in the process of submitting a patch to Clang (https://reviews.llvm.org/D24289) that warns when enums used in bitfields are not given an unsigned underlying type, since MSVC defaults to signed underlying types and this gives inconsistencies when reading/writing the bitfield in multi-platform code.

With the patch, the following code:

enum Foo { A, B };
struct Bar { Foo x : 1 };

will give the following warning with Clang:
"enums in the Microsoft ABI are signed integers by default; consider giving the enum Foo an unsigned underlying type to make this code portable"

But then if it's changed to

enum Foo : unsigned { A, B };
struct Bar { Foo x : 1 };

GCC will give the warning:
"'Bar::x' is too small to hold all values of 'enum Foo'"

The C++ standard says:
9.6.4 says: If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold all the values of that enumeration type (7.2), the original enumerator value and the value of the bit-field shall compare equal.

You can disregard whether the underlying type is fixed or not. So, GCC should not give a warning unless a bitfield containing Foo really is too small to hold a given value of Foo, warning on the assignment makes sense.
Comment 29 Jonathan Wakely 2016-09-28 23:03:24 UTC
(In reply to Sasha B from comment #28)
> You can disregard whether the underlying type is fixed or not. So, GCC
> should not give a warning unless a bitfield containing Foo really is too
> small to hold a given value of Foo, warning on the assignment makes sense.

I agree that we could warn on assignment instead. If the values assigned to the bitfield are constant and known to fit, there's no need to warn. See PR 61414 for the same warning. I don't know if we need to keep both bugs open.
Comment 30 Pavel Revak 2017-10-20 06:22:59 UTC
(In reply to Jonathan Wakely from comment #29)
> (In reply to Sasha B from comment #28)
> > You can disregard whether the underlying type is fixed or not. So, GCC
> > should not give a warning unless a bitfield containing Foo really is too
> > small to hold a given value of Foo, warning on the assignment makes sense.
> 
> I agree that we could warn on assignment instead. If the values assigned to
> the bitfield are constant and known to fit, there's no need to warn. See PR
> 61414 for the same warning. I don't know if we need to keep both bugs open.

Yes I agree that this warning has no sense if the constant don't reach the maximum bits used in bitfield.

Instead of solution where warning is possible to disable with switch will be better to test if maximum constant in enum will fit into bitfield.
Comment 31 Barry Revzin 2020-11-08 18:06:52 UTC
Apparently this was fixed in 9.3?

enum class Color { Red, Green, Blue };

struct X {
    Color c : 2;
};

auto x = X{.c=Color::Red};

warns on 9.2, but not anymore on 9.3 or 10.
Comment 32 Jonathan Wakely 2020-11-09 10:01:24 UTC
(In reply to Barry Revzin from comment #31)
> warns on 9.2, but not anymore on 9.3 or 10.

Changed by r278736 for PR c++/61414

In comment 26 Paolo said this was kept open because of the warning that Jakub fixed, so I'm closing this.