#include <cstdint> #include <initializer_list> int main() { struct{ uint8_t c1:6; uint8_t c2:6; } a; auto c = {a.c1, a.c2}; //warning: narrowing conversion of '(unsigned char)c1' from 'unsigned char' to 'unsigned char:6' [-Wnarrowing] enum class Bool{False=0, True=1}; struct{ Bool v:1; //warning: 'v' is too small to hold all values of 'enum class main()::Bool' } b; return 0; } I get this 2 warnings with g++, including trunk, but not with clang++. I believe the first case is a bug, c1 is promoted to uint8_t and then is truncated back to uint8_t:6. The second case I am not sure if the warning is reasonable. For example clang++ will also not warn if the enum class have values defined that do not fit, and instead will only warn if it detects a assignment that causes truncation.
I think the second is correct but I dont know the exact rules about enum classes; are they unsigned by default? I know normal emuns are signed by default.
Not the case since, same warning if: enum class Bool : uint8_t {False=0, True=1}
Also to add, this could be suppressed if enum class Bool : bool{False=0, True=1}; So a better example is for a 2 bit BitField: enum class Nr : uint8_t{Zero=0, One=1, Two=2, Three=3}; struct{ Nr v:2; } b;
I found that the issue with enum have been extensively debated at #61414. Sorry. So actually this bug report is only regarding the warning with initializer list: struct{ uint8_t c1:6; uint8_t c2:6; } a; auto c = {a.c1, a.c2}; //warning: narrowing conversion of '(unsigned char)c1' from 'unsigned char' to 'unsigned char:6' [-Wnarrowing]
(In reply to Andrew Pinski from comment #1) > I think the second is correct but I dont know the exact rules about enum > classes; are they unsigned by default? No, the default underlying type is 'int'
(In reply to Nuno Gonçalves from comment #4) > I found that the issue with enum have been extensively debated at #61414. > Sorry. Yes, we already have Bug 61414 for that. > So actually this bug report is only regarding the warning with initializer > list: > > struct{ > uint8_t c1:6; > uint8_t c2:6; > } a; > auto c = {a.c1, a.c2}; //warning: narrowing conversion of '(unsigned > char)c1' from 'unsigned char' to 'unsigned char:6' [-Wnarrowing] Confirmed. The initializers should be promoted before deciding the type of the std::initializer_list. This should compile: #include <initializer_list> struct { int c1 : 6; int c2 : 6; } a; auto c = { a.c1, a.c2 }; std::initializer_list<int>& r = c; n.cc:7:14: warning: narrowing conversion of '(int)a.<unnamed struct>::c1' from 'int' to 'signed char:6' [-Wnarrowing] 7 | auto c = { a.c1, a.c2 }; | ~~^~ n.cc:7:14: warning: narrowing conversion of 'a.<unnamed struct>::c1' from 'int' to 'signed char:6' [-Wnarrowing] n.cc:7:20: warning: narrowing conversion of '(int)a.<unnamed struct>::c2' from 'int' to 'signed char:6' [-Wnarrowing] 7 | auto c = { a.c1, a.c2 }; | ~~^~ n.cc:7:20: warning: narrowing conversion of 'a.<unnamed struct>::c2' from 'int' to 'signed char:6' [-Wnarrowing] n.cc:8:33: error: invalid initialization of reference of type 'std::initializer_list<int>&' from expression of type 'std::initializer_list<signed char:6>' 8 | std::initializer_list<int>& r = c; |
Besides bug 61414 this bug also reminds me of bug 39170