Puzzling clang behavior with classes in unions

Hi everyone,

I stumbled upon a piece of code that Visual Studio rejects (and I believe for a good reason), but which clang and gcc both seem to accept (but should not, AFAIK).

I tried to extract a minimal example for this:

class X {
     X(int x) {}

template<class Payload>
class List {
     union PayloadOrNext {
         Payload payload;
         PayloadOrNext *next;

int main(int argc, char **argv)
     List<X> list;

The standard says (in 9.5.1):

"A union can have member functions (including constructors and destructors), but not virtual 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, a non-trivial copy-constructor, a non-trivial destructor, or a non-trivial copy assignment operator 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 a reference type, the program is ill-formed."

X is a class with a non-trivial constructor and is used as a member of the union PayloadOrNext (in the template class List), so I'd expect this code to be rejected. If I use the union directly (still as a template though) or if I replace the template class by a non-template version, the code is indeed rejected.

So my question is: Why does template-with-a-union-member make a difference and what does the generated code actually look like?

Best regards,
  Florian Merz

The latest version of MSVC does not reject:
Compiled with /EHsc /nologo /W4 /c
main.cpp(3): warning C4100: 'x': unreferenced formal parameter
main.cpp(14): warning C4100: 'argv': unreferenced formal parameter
main.cpp(14): warning C4100: 'argc': unreferenced formal parameter
main.cpp(16): warning C4101: 'list': unreferenced local variable

Compilation successful!

Total compilation time: 109ms

You are quoting the C++98 text, C++11 has a feature called "unrestricted
unions": http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf

It looks like there is a bug here though. We allow unrestricted unions in
C++98 mode if the original union declaration is dependent.