Bug 87292 - Warnings with Bit Fields
Summary: Warnings with Bit Fields
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 8.2.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2018-09-13 06:45 UTC by Nuno Gonçalves
Modified: 2018-12-14 04:42 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2018-09-13 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nuno Gonçalves 2018-09-13 06:45:47 UTC
#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.
Comment 1 Andrew Pinski 2018-09-13 06:50:11 UTC
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.
Comment 2 Nuno Gonçalves 2018-09-13 06:51:49 UTC
Not the case since, same warning if:

enum class Bool : uint8_t {False=0, True=1}
Comment 3 Nuno Gonçalves 2018-09-13 06:59:03 UTC
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;
Comment 4 Nuno Gonçalves 2018-09-13 08:00:34 UTC
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]
Comment 5 Jonathan Wakely 2018-09-13 10:06:13 UTC
(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'
Comment 6 Jonathan Wakely 2018-09-13 10:13:37 UTC
(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;
  |
Comment 7 Eric Gallager 2018-12-14 04:42:56 UTC
Besides bug 61414 this bug also reminds me of bug 39170