A union cannot contain static data members or data members of reference type.
authorAnders Carlsson <andersca@mac.com>
Sun, 7 Nov 2010 19:13:55 +0000 (19:13 +0000)
committerAnders Carlsson <andersca@mac.com>
Sun, 7 Nov 2010 19:13:55 +0000 (19:13 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@118381 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclCXX.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDecl.cpp
test/CXX/class/class.union/p1.cpp
test/SemaCXX/member-expr-anonymous-union.cpp

index 8071daadd5601d66731a527cd0ee9e573e8aa517..3fc525e362d5a04acfe0d8dd063c94a5949b24ba 100644 (file)
@@ -341,7 +341,7 @@ class CXXRecordDecl : public RecordDecl {
     
     /// \brief Whether we have already declared a destructor within the class.
     bool DeclaredDestructor : 1;
-    
+
     /// NumBases - The number of base class specifiers in Bases.
     unsigned NumBases;
     
index 33b8660c1d484fbf82cf48c2d6e11a91854a3064..a5b0aa5ec11b1477e42264865d0b16a2596c3e9f 100644 (file)
@@ -674,6 +674,10 @@ def note_nontrivial_has_nontrivial : Note<
 def note_nontrivial_user_defined : Note<
   "because type %0 has a user-declared %select{constructor|copy constructor|"
   "copy assignment operator|destructor}1">;
+def err_static_data_member_not_allowed_in_union_or_anon_struct : Error<
+  "static data member %0 not allowed in %select{anonymous struct|union}1">; 
+def err_union_member_of_reference_type : Error<
+  "union member %0 has reference type %1">;
 
 def err_different_return_type_for_overriding_virtual_function : Error<
   "virtual function %0 has a different return type (%1) than the "
index 10a23ec43ebe675157536e38ca2143b7f0393029..c246cad0989778955657ff7467a84cad170097f4 100644 (file)
@@ -2788,6 +2788,15 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
         Diag(D.getIdentifierLoc(),
              diag::err_static_data_member_not_allowed_in_local_class)
           << Name << RD->getDeclName();
+
+      // C++ [class.union]p1: If a union contains a static data member,
+      // the program is ill-formed.
+      //
+      // We also disallow static data members in anonymous structs.
+      if (CurContext->isRecord() && (RD->isUnion() || !RD->getDeclName()))
+        Diag(D.getIdentifierLoc(),
+             diag::err_static_data_member_not_allowed_in_union_or_anon_struct)
+          << Name << RD->isUnion();
     }
   }
 
@@ -6444,17 +6453,27 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
   }
 
   if (!InvalidDecl && getLangOptions().CPlusPlus) {
-    if (const RecordType *RT = EltTy->getAs<RecordType>()) {
-      CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
-      if (RDecl->getDefinition()) {
-        // C++ 9.5p1: 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.
-        // TODO: C++0x alters this restriction significantly.
-        if (Record->isUnion() && CheckNontrivialField(NewFD))
-          NewFD->setInvalidDecl();
+    if (Record->isUnion()) {
+      if (const RecordType *RT = EltTy->getAs<RecordType>()) {
+        CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
+        if (RDecl->getDefinition()) {
+          // C++ [class.union]p1: 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.
+          // TODO: C++0x alters this restriction significantly.
+          if (CheckNontrivialField(NewFD))
+            NewFD->setInvalidDecl();
+        }
+      }
+
+      // C++ [class.union]p1: If a union contains a member of reference type,
+      // the program is ill-formed.
+      if (EltTy->isReferenceType()) {
+        Diag(NewFD->getLocation(), diag::err_union_member_of_reference_type)
+          << NewFD->getDeclName() << EltTy;
+        NewFD->setInvalidDecl();
       }
     }
   }
index e974d825d6ef5fae07f4079d1de3c3365e6a3386..b5dd4dfd705db296345f3fbeb33808fbfb55e0d7 100644 (file)
@@ -90,6 +90,14 @@ union U3 {
   } m7;
 };
 
+union U4 {
+  static int i1; // expected-error {{static data member 'i1' not allowed in union}}
+};
+
+union U5 {
+  int& i1; // expected-error {{union member 'i1' has reference type 'int &'}}
+};
+
 template <class A, class B> struct Either {
   bool tag;
   union {
index 0f0359667b3893d4f0b9d6b79f75cfc3b1367f49..6e35eb2b14d7d2250f352d5f1a9fc29658dfd8aa 100644 (file)
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 %s -fsyntax-only -verify
 // PR5543
 
-struct A { int x; union { int* y; float& z; }; }; struct B : A {int a;};
+struct A { int x; union { int* y; float* z; }; }; struct B : A {int a;};
 int* a(B* x) { return x->y; }
 
 struct x { union { int y; }; }; x y; template <int X> int f() { return X+y.y; }