Friday, 11 March 2011

Anonymous Union / Struct Weirdness

I've been having a look at clang++ / llvm as this will be the new default compiler for Mac, when I came across the following error in some of my code.

In file included from src/Vector.cpp:17:
include/ngl/Vector.h(476) : error: 'm_x' is a protected member of 'ngl::Vector'
return Vector(_k*_v.m_x, _k*_v.m_y, _k*_v.m_z,_v.m_w);
^
include/ngl/Vector.h(423) : note: declared protected here
Real m_x;
^

This is fair enough however this compiled fine with g++, after turning on the pedantic flag in g++ I got the following error

In file included from src/Vector.cpp:17:
include/ngl/Vector.h:437: error: ISO C++ prohibits anonymous structs

Now this is where the plot thickens and I learnt something new.

So clang++ says I have a visibility problem, whereas g++ running normally says this is fine, and g++ in full pedantic mode say no way, who is correct and what is going on?

A Simple Test Class
To test the problems I was encountering I decided to write a simple class as shown below
class Vector
{

public :
Vector(
const Vector& _v
) :
m_x(_v.m_x),
m_y(_v.m_y),
m_z(_v.m_z),
m_w(_v.m_w){;}

Vector(
const float& _x=0.0,
const float& _y=0.0,
const float& _z=0.0,
const float& _w=1.0f
):
m_x(_x),
m_y(_y),
m_z(_z),
m_w(_w){;}

private :
union
{
struct
{
float m_x;
float m_y;
float m_z;
float m_w;
};
float m_openGL[4];
};

};

So here we have a simple union of 4 floats and an array of 4 floats which if we look at the memory layout would look like this
I then wrote a simple test program which looked like this
int main()
{
Vector v(1.0,2.0,3.0,1.0);
v.m_x=2.0;
std::cout<< v.m_x<<"\n";
}


You will notice in the above program, that I access the member m_x directly. However in the class this is declared in the private section. How does this work?

Well i'm not really sure, according to clang++ "anonymous structs are a GNU extension" so are allowed, however this doesn't account for the breaking of encapsulation.

After further tests I moved the union into the protected area and still it works and I can access the member directly. So it would appear that anonymous struct / unions are always public.

Testing this with Visual Studio 2005 I get the same results, however with the new version of clang++ that ships with Xcode 4 (Apple clang version 2.0 (tags/Apple/clang-137) (based on LLVM 2.9svn)) I get the following

clang++ -pedantic -fdiagnostics-fixit-info VecTest.cpp -o Test
VecTest.cpp:30:5: warning: anonymous structs are a GNU extension [-Wgnu]
struct
^
VecTest.cpp:46:4: error: 'm_x' is a protected member of 'Vector'
v.m_x=2.0;
^
VecTest.cpp:32:13: note: declared protected here
float m_x;
^
VecTest.cpp:47:15: error: 'm_x' is a protected member of 'Vector'
std::cout<<v.m_x<<"\n";
^
VecTest.cpp:32:13: note: declared protected here
float m_x;
^
1 warning and 2 errors generated.

So it seems clang++ deals with the visibility / scope correctly unlike the other two compilers, for now I think I'm going to move the structs in my library to public anyway as this will give me more speed / access for the basic math classes.