Search code examples
c++c++11language-lawyerbit-fieldsenum-class

Enum bitfield and aggregate initialization


The following code is accepted by clang 6.0.0 but rejected by gcc 8.2

enum class E {
  Good, Bad,
};

struct S {
  E e : 2;
  int dummy;
};

S f() {
  return {E::Good, 100};
}

Live godbolt example

The GCC complains

error: could not convert '{Good, 100}' from '<brace-enclosed initializer list>' to 'S'

Which one is correct? Where in the standard talks about this situation?


Solution

  • This should be well-formed and so this is a gcc bug.

    We end up at aggregate initialization via [stmt.return]p2 which says:

    … A return statement with a braced-init-list initializes the object or reference to be returned from the function by copy-list-initialization ([dcl.init.list]) from the specified initializer list. …

    then [dcl.init.list]p3.2 says:

    Otherwise, if T is an aggregate, aggregate initialization is performed ([dcl.init.aggr]). …

    At this point we may wonder if this is a narrowing conversion and therefore ill-formed but [dcl.init.list]p7 does not have any clauses that cover this case and no other cases in [dcl.init.list] apply to make this ill-formed.

    We can see with a similar example which removes enum from the equation but keeps the bit-field shows neither gcc nor clang gives us a narrowing conversion diagnostic, which we expect to be the case, although this similar problem is covered by [dcl.init.list]p7.4 although not ill-formed:

    struct S2 {
        int e : 2 ;
        int dummy ;
    } ;
    
    S2 foo( int x ) {
       return {x, 100} ;
    }
    

    see it live in godbolt

    As observed gcc does not seem to have a problem in other contexts i.e.

    S f(E e1, int x) {  
      S s {e1,100} ;
      return s;
    }
    

    So you do have work-arounds available.