From: Anders Carlsson Date: Sun, 7 Nov 2010 19:13:55 +0000 (+0000) Subject: A union cannot contain static data members or data members of reference type. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dfdfc584f2a8d9f1eebd6e6eaa9b1bbff519d8f9;p=clang A union cannot contain static data members or data members of reference type. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@118381 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 8071daadd5..3fc525e362 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -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; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 33b8660c1d..a5b0aa5ec1 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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 " diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 10a23ec43e..c246cad098 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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()) { - CXXRecordDecl* RDecl = cast(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()) { + CXXRecordDecl* RDecl = cast(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(); } } } diff --git a/test/CXX/class/class.union/p1.cpp b/test/CXX/class/class.union/p1.cpp index e974d825d6..b5dd4dfd70 100644 --- a/test/CXX/class/class.union/p1.cpp +++ b/test/CXX/class/class.union/p1.cpp @@ -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 struct Either { bool tag; union { diff --git a/test/SemaCXX/member-expr-anonymous-union.cpp b/test/SemaCXX/member-expr-anonymous-union.cpp index 0f0359667b..6e35eb2b14 100644 --- a/test/SemaCXX/member-expr-anonymous-union.cpp +++ b/test/SemaCXX/member-expr-anonymous-union.cpp @@ -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 f() { return X+y.y; }