Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a GCC bug? Initializing structs with unions

I may have found a bug with GCC v4.8.2, but I want to check first before I submit it as it could be me doing something wrong!

The following code:

#include <vector>
struct Message
{
  typedef union {
    char byte;
    const char *str;
  } Parameter;

  Parameter p1;
  Parameter p2;
};

int main()
{
  std::vector<Message> messages_;

  messages_.push_back({{ .byte = 'a' }});

  Message message = {{ .byte = 'a' }, { .str = "Hello World" }};
  messages_.push_back(message);

  messages_.push_back({{ .byte = 'a' }, { .str = "Hello World" }});
}

clang++ -std=c++11 main.cpp compiles this fine. However g++ outputs this:

main.cpp: In function ‘int main()’:
main.cpp:23:66: internal compiler error: in reshape_init_class, at cp/decl.c:5216
   messages_.push_back({{ .byte = 'a' }, { .str = "Hello World" }});
                                                                  ^
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://bugzilla.redhat.com/bugzilla> for instructions.
Preprocessed source stored into /tmp/ccrf5vwr.out file, please attach this to your bugreport.

I'll submit this as a bug if nobody has any ideas, although in my experience a programmers problem is almost never a compiler bug and almost always a fault of his own!

like image 327
Sam Kellett Avatar asked Feb 05 '14 13:02

Sam Kellett


1 Answers

As answered in the comments above: Any error message you get from GCC that includes the phrases internal compiler error and Please submit a full bug report is definitely a compiler bug, not your own fault! In this case, the bug appears to be something to do with GCC's parsing of {{ ... }} in C++ mode where the "..." includes a designated initializer. @Sam has reported it as GCC bug 59832.

However, as @Angew pointed out, this line —

messages_.push_back({{ .byte = 'a' }});

— is not valid C++. Standard C++ doesn't allow designated initializers; that's a C99 feature that was not adopted into C++ (neither C++11 nor C++14).

As for why designated initializers have been problematic to add to C++, see here, where Doug Gregor asks how the compiler should interpret things like

struct Foo {int x,y; };
void f(Foo);
void f(std::initializer_list<int>);

int main(){
    f({1});
    f({1,2});
    f({1,2,3});
    f({.x=1});
    f({.x=1,2});
    f({.x=1,2,3});
}

For the record, GCC 4.8 treats all six as calls to f(initializer_list<int>). Clang 3.5 treats the first three as calls to f(initializer_list<int>), the next two as calls to f(Foo), and the last one as ill-formed. Basically, it's a non-standard construct: different compilers are within their rights to treat it differently, and they do.

like image 196
Quuxplusone Avatar answered Oct 25 '22 23:10

Quuxplusone