From 556e5860f970411bec3f440c1cb20563b51a77a6 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 10 Oct 2011 17:22:13 +0000 Subject: [PATCH] Per C++ [class.bit]p2, unnamed bit-fields are not members. Fixes PR10289. llvm-svn: 141549 --- clang/lib/AST/DeclCXX.cpp | 7 +++++ clang/lib/Sema/SemaDeclCXX.cpp | 40 ++++++++++++++++++++++++--- clang/lib/Sema/SemaInit.cpp | 2 +- clang/test/CXX/class/class.bit/p2.cpp | 22 +++++++++++++++ 4 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 clang/test/CXX/class/class.bit/p2.cpp diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 9addece6f96c..5dcecb9a1101 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -653,6 +653,13 @@ NotASpecialMember:; // Handle non-static data members. if (FieldDecl *Field = dyn_cast(D)) { + // C++ [class.bit]p2: + // A declaration for a bit-field that omits the identifier declares an + // unnamed bit-field. Unnamed bit-fields are not members and cannot be + // initialized. + if (Field->isUnnamedBitfield()) + return; + // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with [...] no // private or protected non-static data members (clause 11). diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 4f9c0493c674..ea0b06bacb44 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -810,6 +810,9 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef, FieldDecl *Field, llvm::SmallSet &Inits, bool &Diagnosed) { + if (Field->isUnnamedBitfield()) + return; + if (!Inits.count(Field)) { if (!Diagnosed) { SemaRef.Diag(Dcl->getLocation(), diag::err_constexpr_ctor_missing_init); @@ -2816,6 +2819,13 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, MemEnd = ClassDecl->decls_end(); Mem != MemEnd; ++Mem) { if (FieldDecl *F = dyn_cast(*Mem)) { + // C++ [class.bit]p2: + // A declaration for a bit-field that omits the identifier declares an + // unnamed bit-field. Unnamed bit-fields are not members and cannot be + // initialized. + if (F->isUnnamedBitfield()) + continue; + if (F->getType()->isIncompleteArrayType()) { assert(ClassDecl->hasFlexibleArrayMember() && "Incomplete array type is not valid"); @@ -2956,9 +2966,13 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, // 3. Direct fields. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - E = ClassDecl->field_end(); Field != E; ++Field) + E = ClassDecl->field_end(); Field != E; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + IdealInitKeys.push_back(GetKeyForTopLevelField(*Field)); - + } + unsigned NumIdealInits = IdealInitKeys.size(); unsigned IdealIndex = 0; @@ -3530,7 +3544,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { for (RecordDecl::field_iterator F = Record->field_begin(), FEnd = Record->field_end(); F != FEnd; ++F) { - if (F->hasInClassInitializer()) + if (F->hasInClassInitializer() || F->isUnnamedBitfield()) continue; if (F->getType()->isReferenceType() || @@ -4202,7 +4216,7 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM) { for (CXXRecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) { - if (FI->isInvalidDecl()) + if (FI->isInvalidDecl() || FI->isUnnamedBitfield()) continue; QualType FieldType = Context.getBaseElementType(FI->getType()); @@ -4402,6 +4416,9 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { for (CXXRecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) { + if (FI->isUnnamedBitfield()) + continue; + QualType FieldType = Context.getBaseElementType(FI->getType()); // -- for a copy constructor, a non-static data member of rvalue reference @@ -4539,6 +4556,9 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { for (CXXRecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) { + if (FI->isUnnamedBitfield()) + continue; + QualType FieldType = Context.getBaseElementType(FI->getType()); // -- a non-static data member of reference type @@ -4695,6 +4715,9 @@ bool Sema::ShouldDeleteMoveConstructor(CXXConstructorDecl *CD) { for (CXXRecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) { + if (FI->isUnnamedBitfield()) + continue; + QualType FieldType = Context.getBaseElementType(FI->getType()); if (CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl()) { @@ -4815,6 +4838,9 @@ bool Sema::ShouldDeleteMoveAssignmentOperator(CXXMethodDecl *MD) { for (CXXRecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) { + if (FI->isUnnamedBitfield()) + continue; + QualType FieldType = Context.getBaseElementType(FI->getType()); // -- a non-static data member of reference type @@ -7922,6 +7948,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + // Check for members of reference type; we can't copy those. if (Field->getType()->isReferenceType()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) @@ -8340,6 +8369,9 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + // Check for members of reference type; we can't move those. if (Field->getType()->isReferenceType()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index f5cfbcafb4a8..e9d4b82c8c66 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -490,7 +490,7 @@ int InitListChecker::numStructUnionElements(QualType DeclType) { Field = structDecl->field_begin(), FieldEnd = structDecl->field_end(); Field != FieldEnd; ++Field) { - if ((*Field)->getIdentifier() || !(*Field)->isBitField()) + if (!Field->isUnnamedBitfield()) ++InitializableMembers; } if (structDecl->isUnion()) diff --git a/clang/test/CXX/class/class.bit/p2.cpp b/clang/test/CXX/class/class.bit/p2.cpp new file mode 100644 index 000000000000..a849664593d1 --- /dev/null +++ b/clang/test/CXX/class/class.bit/p2.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s + +struct A { +private: + int : 0; +}; + +A a = { }; +A a2 = { 1 }; // expected-error{{excess elements in struct initializer}} + +struct B { + const int : 0; +}; + +B b; + +void testB() { + B b2(b); + B b3(static_cast(b2)); + b = b; + b = static_cast(b); +}