With this code:
struct A
{
int i;
const int b;
};
// The union is to verify that A is a type that can be used in a union.
union U
{
A a;
int b;
};
int main()
{
U a = {1, 1};
U b = {2, 1};
}
g++ version 4.8.3 complains about an error:
a.cpp:9:4: error: member ‘A U::a’ with copy assignment operator not allowed in union
A a;
^
a.cpp:9:4: note: unrestricted unions only available with -std=c++11 or -std=gnu++11
but clang 3.5.0 compiles this code without error. Which one is correct? Is this a compiler bug?
My attempt at solving this:
From the C++03 standard section 9.5 paragraph 1:
In a union, at most one of the data members can be active at any time, that is, the value of at most one of the data members can be stored in a union at any time. [Note: one special guarantee is made in order to simplify the use of unions: If a POD-union contains several POD-structs that share a common initial sequence (9.2), and if an object of this POD-union type contains one of the POD-structs, it is permitted to inspect the common initial sequence of any of POD-struct members; see 9.2. ] The size of a union is sufficient to contain the largest of its data members. Each data member is allocated as if it were the sole member of a struct. A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class. An object of a class with a non-trivial constructor (12.1), a non-trivial copy constructor (12.8), a non-trivial destructor (12.4), or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a member of a union, nor can an array of such objects. If a union contains a static data member, or a member of reference type, the program is ill-formed.
From the C++03 standard section 12.8 paragraphs 10 and 11:
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. The implicitly-declared copy assignment operator for a class X will have the form
X& X::operator=(const X&)
if each direct base class B of X has a copy assignment operator whose parameter is of type const B&, const volatile B& or B, and for all the nonstatic data members of X that are of a class type M (or array thereof), each such class type has a copy assignment operator whose parameter is of type const M&, const volatile M& or M.
Otherwise, the implicitly declared copy assignment operator will have the form X& X::operator=(X&)
...A copy assignment operator for class X is trivial if it is implicitly declared and if class X has no virtual functions (10.3) and no virtual base classes (10.1), and each direct base class of X has a trivial copy assignment operator, and for all the nonstatic data members of X that are of class type (or array thereof), each such class type has a trivial copy assignment operator; otherwise the copy assignment operator is non-trivial.
I'm not sure which compiler is correct because I don't know if a constant member has a trivial copy assignment operator.
Edit: The compilation commands are:
clang++ a.cpp -o a
g++ a.cpp -o a
Edit2:
To show that g++ isn't complaining about A::b being const
but A doesn't have a constructor, I also tried this program:
struct A
{
int i;
const int b;
};
int main()
{
A a = {1, 1};
}
This compiled without errors on both g++ and clang++:
g++ b.cpp -o b
clang++ b.cpp -o b