jww jww - 2 months ago 10
C++ Question

SunCC 5.12 through 5.14 and "Types cannot be declared in anonymous union"

We are catching a compile warning under SunCC 5.12 through 5.14. Other compilers, like Clang, GCC, ICC and MSVC does not complain. I'm not sure about the diagnostic because I have not encountered it before.

The code in question is for a

class and the problematic union follows. The class attempts to find the largest machine word that can accommodate adds-with-carries and multiplies that can be performed using hardware like
umulx
.

class Dword
{
...
private:
320 union
321 {
322 #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE
323 dword m_whole;
324 #endif
325 struct
326 {
327 #ifdef IS_LITTLE_ENDIAN
328 word low;
329 word high;
330 #else
331 word high;
332 word low;
333 #endif
334 } m_halfs;
335 };
336 };


Here's the warning:

[ 3%] Building CXX object CMakeFiles/cryptopp-object.dir/integer.cpp.o
/opt/solarisstudio12.3/bin/CC -fPIC -native -m64 -template=no%extdef -o CMakeFiles/cryptopp-object.dir/integer.cpp.o
-c /export/home/jwalton/cryptopp/integer.cpp
CC: Warning: -xchip=native detection failed, falling back to -xchip=generic
"/export/home/jwalton/cryptopp/integer.cpp", line 335: Warning: Types cannot be declared in anonymous union.
1 Warning(s) detected.


According to Microsoft at Anonymous Unions:


Simply omitting the class-name portion of the syntax does not make a union an anonymous union. For a union to qualify as an anonymous union, the declaration must not declare an object.


If I understand things correctly, we do have an anonymous struct because no one can instantiate the private member
struct {...} m_halfs
starting at line 325. Then, SunCC is complaining the anonymous union has the member
struct {...} m_halfs
. Is that correct?

If
struct {...} m_halfs
is the problem, then how can we go about clearing it in a portable way?

If its not the problem, then what is SunCC complaining about?




I have to be careful about how this issue cleared. Performance is a top priority and the code is on the critical path. Also, we support GCC 3 and VC++ 6.0 to contemporary compilers; and C++03, C++11, C++14 and C++17.

A final question is, should we "do nothing" and live with it on Solaris?

Answer

N4296 (which is the latest draft of the C++ 17 standard) says:

A union of the form

      union { member-specification } ; 

is called an anonymous union; it defines an unnamed object of unnamed type. Each member-declaration in the member-specification of an anonymous union shall either define a non-static data member or be a static_assert-declaration. [ Note: Nested types, anonymous unions, and functions cannot be declared within an anonymous union. — end note]

That is exactly what you have here - you don't have a class name or a member name, so you are not allowed to invent a new struct type for m_halfs. I suggest moving the struct definition out of the union.

   class Dword
   {
     ...
     private:
        struct word_struct
        {
        #ifdef IS_LITTLE_ENDIAN
            word low;
            word high;
        #else
            word high;
            word low;
        #endif
       };
       union
       {
       #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE
           dword m_whole;
       #endif
           word_struct m_halfs;
       };
   };

This will have no impact on performance (but note that this trick of using unions to access different parts of a variable may fall foul of the strict aliasing rules - which means your program may have undefined behaviour.)