Index: AST/ASTImporter.cpp =================================================================== --- AST/ASTImporter.cpp +++ AST/ASTImporter.cpp @@ -1071,7 +1071,7 @@ ToData.Polymorphic = FromData.Polymorphic; ToData.Abstract = FromData.Abstract; ToData.IsStandardLayout = FromData.IsStandardLayout; - ToData.HasNoNonEmptyBases = FromData.HasNoNonEmptyBases; + ToData.HasBasesWithFields = FromData.HasBasesWithFields; ToData.HasPrivateFields = FromData.HasPrivateFields; ToData.HasProtectedFields = FromData.HasProtectedFields; ToData.HasPublicFields = FromData.HasPublicFields; Index: AST/DeclCXX.cpp =================================================================== --- AST/DeclCXX.cpp +++ AST/DeclCXX.cpp @@ -74,7 +74,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0), Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), - Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true), + Abstract(false), IsStandardLayout(true), HasBasesWithFields(false), HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), HasMutableFields(false), HasVariantMembers(false), HasOnlyCMembers(true), HasInClassInitializer(false), @@ -162,6 +162,25 @@ return R; } +/// Determine whether a class has a repeated base class. This is intended for +/// use when determining if a class is standard-layout, so makes no attempt to +/// handle virtual bases. +static bool hasRepeatedBaseClass(const CXXRecordDecl *StartRD) { + llvm::SmallPtrSet SeenBaseTypes; + SmallVector WorkList = {StartRD}; + while (!WorkList.empty()) { + const CXXRecordDecl *RD = WorkList.pop_back_val(); + for (const CXXBaseSpecifier &BaseSpec : RD->bases()) { + if (const CXXRecordDecl *B = BaseSpec.getType()->getAsCXXRecordDecl()) { + if (!SeenBaseTypes.insert(B).second) + return true; + WorkList.push_back(B); + } + } + } + return false; +} + void CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases) { @@ -201,26 +220,30 @@ CXXRecordDecl *BaseClassDecl = cast(BaseType->getAs()->getDecl()); - if (!BaseClassDecl->isEmpty()) { - if (!data().Empty) { - // C++0x [class]p7: - // A standard-layout class is a class that: - // [...] - // -- either has no non-static data members in the most derived - // class and at most one base class with non-static data members, - // or has no base classes with non-static data members, and - // If this is the second non-empty base, then neither of these two - // clauses can be true. + // [DR1813] In Clang 6 and earlier, we allowed length 0 bit-fields in + // base classes of a standard-layout class. + if (BaseClassDecl->data().HasBasesWithFields || + (C.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver6 + ? !BaseClassDecl->data().Empty + : !BaseClassDecl->field_empty())) { + // C++2a [class]p7: + // A standard-layout class is a class that: + // [...] + // -- has all non-static data members and bit-fields in the class and + // its base classes first declared in the same class + if (data().HasBasesWithFields) + // Two bases have members or bit-fields: not standard-layout. data().IsStandardLayout = false; - } + data().HasBasesWithFields = true; + } + if (!BaseClassDecl->isEmpty()) { // C++14 [meta.unary.prop]p4: // T is a class type [...] with [...] no base class B for which // is_empty::value is false. data().Empty = false; - data().HasNoNonEmptyBases = false; } - + // C++1z [dcl.init.agg]p1: // An aggregate is a class with [...] no private or protected base classes if (Base->getAccessSpecifier() != AS_public) @@ -402,6 +425,18 @@ addedClassSubobject(BaseClassDecl); } + + // C++2a [class]p7: + // A class S is a standard-layout class if it: + // -- has at most one base class subobject of any given type + // + // Note that we only need to check this for classes with more than one base + // class. If there's only one base class, and it's standard layout, then + // we know there are no repeated base classes. + if (data().IsStandardLayout && NumBases > 1 && + (C.getLangOpts().getClangABICompat() > LangOptions::ClangABI::Ver6) && + hasRepeatedBaseClass(this)) + data().IsStandardLayout = false; if (VBases.empty()) { data().IsParsingBaseSpecifiers = false; @@ -502,6 +537,81 @@ data().Abstract = true; } +bool CXXRecordDecl::hasSubobjectAtOffsetZeroOfEmptyBaseType( + ASTContext &Ctx, const CXXRecordDecl *XFirst) { + if (!getNumBases()) + return false; + + llvm::SmallPtrSet Bases; + llvm::SmallPtrSet M; + SmallVector WorkList; + + // Visit a type that we have determined is an element of M(S). + auto Visit = [&](const CXXRecordDecl *RD) -> bool { + RD = RD->getCanonicalDecl(); + + // C++2a [class]p8: + // A class S is a standard-layout class if it [...] has no element of the + // set M(S) of types as a base class. + // + // If we find a subobject of an empty type, it might also be a base class, + // so we'll need to walk the base classes to check. + if (!RD->data().HasBasesWithFields) { + // Walk the bases the first time, stopping if we find the type. Build a + // set of them so we don't need to walk them again. + if (Bases.empty()) { + bool RDIsBase = !forallBases([&](const CXXRecordDecl *Base) -> bool { + Base = Base->getCanonicalDecl(); + if (RD == Base) + return false; + Bases.insert(Base); + return true; + }); + if (RDIsBase) + return true; + } else { + if (Bases.count(RD)) + return true; + } + } + + if (M.insert(RD).second) + WorkList.push_back(RD); + return false; + }; + + if (Visit(XFirst)) + return true; + + while (!WorkList.empty()) { + const CXXRecordDecl *X = WorkList.pop_back_val(); + + // FIXME: We don't check the bases of X. That matches the standard, but + // that sure looks like a wording bug. + + // -- If X is a non-union class type with a non-static data member + // [recurse to] the first non-static data member of X + // -- If X is a union type, [recurse to union members] + for (auto *FD : X->fields()) { + // FIXME: Should we really care about the type of the first non-static + // data member of a non-union if there are preceding unnamed bit-fields? + if (FD->isUnnamedBitfield()) + continue; + + // -- If X is n array type, [visit the element type] + QualType T = Ctx.getBaseElementType(FD->getType()); + if (auto *RD = T->getAsCXXRecordDecl()) + if (Visit(RD)) + return true; + + if (!X->isUnion()) + break; + } + } + + return false; +} + void CXXRecordDecl::addedMember(Decl *D) { if (!D->isImplicit() && !isa(D) && @@ -735,8 +845,21 @@ return; } + ASTContext &Context = getASTContext(); + // Handle non-static data members. if (FieldDecl *Field = dyn_cast(D)) { + // C++2a [class]p7: + // A standard-layout class is a class that: + // [...] + // -- has all non-static data members and bit-fields in the class and + // its base classes first declared in the same class + if (data().HasBasesWithFields && + (Context.getLangOpts().getClangABICompat() > + LangOptions::ClangABI::Ver6 || + !Field->isUnnamedBitfield())) + data().IsStandardLayout = false; + // 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 @@ -754,6 +877,11 @@ data().PlainOldData = false; } + // Track whether this is the first field. We use this when checking + // whether the class is standard-layout below. + bool IsFirstField = !data().HasPrivateFields && + !data().HasProtectedFields && !data().HasPublicFields; + // C++0x [class]p7: // A standard-layout class is a class that: // [...] @@ -787,7 +915,6 @@ // // Automatic Reference Counting: the presence of a member of Objective-C pointer type // that does not explicitly have no lifetime makes the class a non-POD. - ASTContext &Context = getASTContext(); QualType T = Context.getBaseElementType(Field->getType()); if (T->isObjCRetainableType() || T.isObjCGCStrong()) { if (T.hasNonTrivialObjCLifetime()) { @@ -984,30 +1111,30 @@ if (!FieldRec->isStandardLayout()) data().IsStandardLayout = false; - // C++0x [class]p7: + // C++2a [class]p7: // A standard-layout class is a class that: // [...] - // -- has no base classes of the same type as the first non-static - // data member. - // We don't want to expend bits in the state of the record decl - // tracking whether this is the first non-static data member so we - // cheat a bit and use some of the existing state: the empty bit. - // Virtual bases and virtual methods make a class non-empty, but they - // also make it non-standard-layout so we needn't check here. - // A non-empty base class may leave the class standard-layout, but not - // if we have arrived here, and have at least one non-static data - // member. If IsStandardLayout remains true, then the first non-static - // data member must come through here with Empty still true, and Empty - // will subsequently be set to false below. - if (data().IsStandardLayout && data().Empty) { - for (const auto &BI : bases()) { - if (Context.hasSameUnqualifiedType(BI.getType(), T)) { + // -- has no element of the set M(S) of types as a base class. + if (data().IsStandardLayout) { + if (Context.getLangOpts().getClangABICompat() > + LangOptions::ClangABI::Ver6) { + if ((isUnion() || IsFirstField) && + hasSubobjectAtOffsetZeroOfEmptyBaseType(Context, FieldRec)) data().IsStandardLayout = false; - break; + } else { + // Clang 6 compatibility: ignore all but the first field of unions, + // don't check for subobject collisions. + if (data().Empty) { + for (const auto &BI : bases()) { + if (Context.hasSameUnqualifiedType(BI.getType(), T)) { + data().IsStandardLayout = false; + break; + } + } } } } - + // Keep track of the presence of mutable fields. if (FieldRec->hasMutableFields()) { data().HasMutableFields = true; @@ -1070,17 +1197,6 @@ data().DefaultedMoveAssignmentIsDeleted = true; } - // C++0x [class]p7: - // A standard-layout class is a class that: - // [...] - // -- either has no non-static data members in the most derived - // class and at most one base class with non-static data members, - // or has no base classes with non-static data members, and - // At this point we know that we have a non-static data member, so the last - // clause holds. - if (!data().HasNoNonEmptyBases) - data().IsStandardLayout = false; - // C++14 [meta.unary.prop]p4: // T is a class type [...] with [...] no non-static data members other // than bit-fields of length 0... Index: CXX/drs/dr14xx.cpp =================================================================== --- CXX/drs/dr14xx.cpp +++ CXX/drs/dr14xx.cpp @@ -7,6 +7,8 @@ // expected-no-diagnostics #endif +// dr1425: na abi + namespace dr1460 { // dr1460: 3.5 #if __cplusplus >= 201103L namespace DRExample { Index: CXX/drs/dr16xx.cpp =================================================================== --- CXX/drs/dr16xx.cpp +++ CXX/drs/dr16xx.cpp @@ -3,6 +3,11 @@ // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +#if __cplusplus < 201103L +// expected-error@+1 {{variadic macro}} +#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__) +#endif + namespace dr1611 { // dr1611: dup 1658 struct A { A(int); }; struct B : virtual A { virtual void f() = 0; }; @@ -219,3 +224,28 @@ // assignment case is superseded by dr2180 } + +namespace dr1672 { // dr1672: 7 + struct Empty {}; + struct A : Empty {}; + struct B { Empty e; }; + struct C : A { B b; int n; }; + struct D : A { int n; B b; }; + + static_assert(!__is_standard_layout(C), ""); + static_assert(__is_standard_layout(D), ""); + + struct E { B b; int n; }; + struct F { int n; B b; }; + union G { B b; int n; }; + union H { int n; B b; }; + + struct X {}; + template struct Y : X, A { T t; }; + + static_assert(!__is_standard_layout(Y), ""); + static_assert(__is_standard_layout(Y), ""); + static_assert(!__is_standard_layout(Y), ""); + static_assert(!__is_standard_layout(Y), ""); + static_assert(!__is_standard_layout(Y), ""); +} Index: CXX/drs/dr18xx.cpp =================================================================== --- CXX/drs/dr18xx.cpp +++ CXX/drs/dr18xx.cpp @@ -4,9 +4,44 @@ // RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors #if __cplusplus < 201103L -// expected-no-diagnostics +// expected-error@+1 {{variadic macro}} +#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__) #endif +namespace dr1813 { // dr1813: 7 + struct B { int i; }; + struct C : B {}; + struct D : C {}; + struct E : D { char : 4; }; + + static_assert(__is_standard_layout(B), ""); + static_assert(__is_standard_layout(C), ""); + static_assert(__is_standard_layout(D), ""); + static_assert(!__is_standard_layout(E), ""); + + struct Q {}; + struct S : Q {}; + struct T : Q {}; + struct U : S, T {}; + + static_assert(__is_standard_layout(Q), ""); + static_assert(__is_standard_layout(S), ""); + static_assert(__is_standard_layout(T), ""); + static_assert(!__is_standard_layout(U), ""); +} + +namespace dr1881 { // dr1881: 7 + struct A { int a : 4; }; + struct B : A { int b : 3; }; + static_assert(__is_standard_layout(A), ""); + static_assert(!__is_standard_layout(B), ""); + + struct C { int : 0; }; + struct D : C { int : 0; }; + static_assert(__is_standard_layout(C), ""); + static_assert(!__is_standard_layout(D), ""); +} + void dr1891() { // dr1891: 4 #if __cplusplus >= 201103L int n; Index: CXX/drs/dr21xx.cpp =================================================================== --- CXX/drs/dr21xx.cpp +++ CXX/drs/dr21xx.cpp @@ -3,6 +3,22 @@ // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +#if __cplusplus < 201103L +// expected-error@+1 {{variadic macro}} +#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__) +#endif + +namespace dr2120 { // dr2120: 7 + struct A {}; + struct B : A {}; + struct C { A a; }; + struct D { C c[5]; }; + struct E : B { D d; }; + static_assert(__is_standard_layout(B), ""); + static_assert(__is_standard_layout(D), ""); + static_assert(!__is_standard_layout(E), ""); +} + namespace dr2180 { // dr2180: yes class A { A &operator=(const A &); // expected-note 0-2{{here}} Index: CXX/drs/dr22xx.cpp =================================================================== --- CXX/drs/dr22xx.cpp +++ CXX/drs/dr22xx.cpp @@ -3,7 +3,7 @@ // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -namespace dr2229 { // dr2229: yes +namespace dr2229 { // dr2229: 7 struct AnonBitfieldQualifiers { const unsigned : 1; // expected-error {{anonymous bit-field cannot have qualifiers}} volatile unsigned : 1; // expected-error {{anonymous bit-field cannot have qualifiers}} Index: Layout/v6-standard-layout.cpp =================================================================== --- /dev/null +++ Layout/v6-standard-layout.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -fsyntax-only -fclang-abi-compat=6 -triple armv7k-apple-darwin-watchos -fdump-record-layouts %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V6 +// RUN: %clang_cc1 -fsyntax-only -fclang-abi-compat=7 -triple armv7k-apple-darwin-watchos -fdump-record-layouts %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V7 + +// In Clang 6 and before, we determined that B was standard-layout, so we +// didn't pack C::d into its tail padding. +struct A { int : 4; }; +struct B : A { int n; char c[3]; }; +struct C : B { char d; }; +int c = sizeof(C); + +// CHECK:*** Dumping AST Record Layout +// CHECK: 0 | struct C +// CHECK-NEXT: 0 | struct B (base) +// CHECK-NEXT: 0 | struct A (base) (empty) +// CHECK-NEXT: 0:0-3 | int +// CHECK-NEXT: 0 | int n +// CHECK-NEXT: 4 | char [3] c +// CHECK-V6-NEXT: 8 | char d +// CHECK-V6-NEXT: | [sizeof=12, dsize=9, align=4, +// CHECK-V6-NEXT: | nvsize=9, nvalign=4] +// CHECK-V7-NEXT: 7 | char d +// CHECK-V7-NEXT: | [sizeof=8, dsize=8, align=4, +// CHECK-V7-NEXT: | nvsize=8, nvalign=4] + +// In Clang 6 and before, we determined that F was standard-layout despite it +// having multiple empty base classes of the same type. +struct D {}; +struct E : D {}; +struct F : D, E { int n; char c[3]; }; +struct G : F { G(const G&); char d; }; +int g = sizeof(G); + +// CHECK:*** Dumping AST Record Layout +// CHECK: 0 | struct G +// CHECK-NEXT: 0 | struct F (base) +// CHECK-NEXT: 0 | struct D (base) (empty) +// CHECK-NEXT: 1 | struct E (base) (empty) +// CHECK-NEXT: 1 | struct D (base) (empty) +// CHECK-NEXT: 0 | int n +// CHECK-NEXT: 4 | char [3] c +// CHECK-V6-NEXT: 8 | char d +// CHECK-V6-NEXT: | [sizeof=12, dsize=9, align=4, +// CHECK-V6-NEXT: | nvsize=9, nvalign=4] +// CHECK-V7-NEXT: 7 | char d +// CHECK-V7-NEXT: | [sizeof=8, dsize=8, align=4, +// CHECK-V7-NEXT: | nvsize=8, nvalign=4] Index: ReleaseNotes.rst =================================================================== --- ReleaseNotes.rst +++ ReleaseNotes.rst @@ -65,6 +65,15 @@ - clang binary and libraries have been renamed from 7.0 to 7. For example, the clang binary will be called clang-7 instead of clang-7.0. +- Clang implements a collection of recent fixes to the C++ standard's definition + of "standard-layout". In particular, a class is only considered to be + standard-layout if all base classes and the first data member (or bit-field) + can be laid out at offset zero. This unfortunately results in an ABI break + for ABIs that base their choice to reuse base class tail padding on whether + the base class is standard-layout (64-bit iOS, WatchOS, and WebAssembly). + The old behavior can be restored by setting ``-fclang-abi-compat`` to ``6`` + or lower. + - ... New Compiler Flags Index: SemaCXX/type-traits.cpp =================================================================== --- SemaCXX/type-traits.cpp +++ SemaCXX/type-traits.cpp @@ -1353,6 +1353,59 @@ int t43[F(__is_standard_layout(AnIncompleteType[1]))]; // expected-error {{incomplete type}} int t44[F(__is_standard_layout(void))]; int t45[F(__is_standard_layout(const volatile void))]; + + struct HasAnonEmptyBitfield { int : 0; }; + struct HasAnonBitfield { int : 4; }; + struct DerivesFromBitfield : HasAnonBitfield {}; + struct DerivesFromBitfieldWithBitfield : HasAnonBitfield { int : 5; }; + struct DerivesFromBitfieldTwice : DerivesFromBitfield, HasAnonEmptyBitfield {}; + + int t50[T(__is_standard_layout(HasAnonEmptyBitfield))]; + int t51[T(__is_standard_layout(HasAnonBitfield))]; + int t52[T(__is_standard_layout(DerivesFromBitfield))]; + int t53[F(__is_standard_layout(DerivesFromBitfieldWithBitfield))]; + int t54[F(__is_standard_layout(DerivesFromBitfieldTwice))]; + + struct Empty {}; + struct HasEmptyBase : Empty {}; + struct HoldsEmptyBase { Empty e; }; + struct HasRepeatedEmptyBase : Empty, HasEmptyBase {}; // expected-warning {{inaccessible}} + struct HasEmptyBaseAsMember : Empty { Empty e; }; + struct HasEmptyBaseAsSubobjectOfMember1 : Empty { HoldsEmptyBase e; }; + struct HasEmptyBaseAsSubobjectOfMember2 : Empty { HasEmptyBase e; }; + struct HasEmptyBaseAsSubobjectOfMember3 : Empty { HoldsEmptyBase e[2]; }; + struct HasEmptyIndirectBaseAsMember : HasEmptyBase { Empty e; }; + struct HasEmptyIndirectBaseAsSecondMember : HasEmptyBase { int n; Empty e; }; + struct HasEmptyIndirectBaseAfterBitfield : HasEmptyBase { int : 4; Empty e; }; + + int t60[T(__is_standard_layout(Empty))]; + int t61[T(__is_standard_layout(HasEmptyBase))]; + int t62[F(__is_standard_layout(HasRepeatedEmptyBase))]; + int t63[F(__is_standard_layout(HasEmptyBaseAsMember))]; + int t64[F(__is_standard_layout(HasEmptyBaseAsSubobjectOfMember1))]; + int t65[T(__is_standard_layout(HasEmptyBaseAsSubobjectOfMember2))]; // FIXME: standard bug? + int t66[F(__is_standard_layout(HasEmptyBaseAsSubobjectOfMember3))]; + int t67[F(__is_standard_layout(HasEmptyIndirectBaseAsMember))]; + int t68[T(__is_standard_layout(HasEmptyIndirectBaseAsSecondMember))]; + int t69[F(__is_standard_layout(HasEmptyIndirectBaseAfterBitfield))]; // FIXME: standard bug? + + struct StructWithEmptyFields { + int n; + HoldsEmptyBase e[3]; + }; + union UnionWithEmptyFields { + int n; + HoldsEmptyBase e[3]; + }; + struct HasEmptyIndirectBaseAsSecondStructMember : HasEmptyBase { + StructWithEmptyFields u; + }; + struct HasEmptyIndirectBaseAsSecondUnionMember : HasEmptyBase { + UnionWithEmptyFields u; + }; + + int t70[T(__is_standard_layout(HasEmptyIndirectBaseAsSecondStructMember))]; + int t71[F(__is_standard_layout(HasEmptyIndirectBaseAsSecondUnionMember))]; } void is_signed() Index: Serialization/ASTReaderDecl.cpp =================================================================== --- Serialization/ASTReaderDecl.cpp +++ Serialization/ASTReaderDecl.cpp @@ -1563,7 +1563,7 @@ Data.Polymorphic = Record.readInt(); Data.Abstract = Record.readInt(); Data.IsStandardLayout = Record.readInt(); - Data.HasNoNonEmptyBases = Record.readInt(); + Data.HasBasesWithFields = Record.readInt(); Data.HasPrivateFields = Record.readInt(); Data.HasProtectedFields = Record.readInt(); Data.HasPublicFields = Record.readInt(); @@ -1702,7 +1702,7 @@ MATCH_FIELD(Polymorphic) MATCH_FIELD(Abstract) MATCH_FIELD(IsStandardLayout) - MATCH_FIELD(HasNoNonEmptyBases) + MATCH_FIELD(HasBasesWithFields) MATCH_FIELD(HasPrivateFields) MATCH_FIELD(HasProtectedFields) MATCH_FIELD(HasPublicFields) Index: Serialization/ASTWriter.cpp =================================================================== --- Serialization/ASTWriter.cpp +++ Serialization/ASTWriter.cpp @@ -5995,7 +5995,7 @@ Record->push_back(Data.Polymorphic); Record->push_back(Data.Abstract); Record->push_back(Data.IsStandardLayout); - Record->push_back(Data.HasNoNonEmptyBases); + Record->push_back(Data.HasBasesWithFields); Record->push_back(Data.HasPrivateFields); Record->push_back(Data.HasProtectedFields); Record->push_back(Data.HasPublicFields); Index: clang/AST/DeclCXX.h =================================================================== --- clang/AST/DeclCXX.h +++ clang/AST/DeclCXX.h @@ -363,11 +363,11 @@ /// member. unsigned IsStandardLayout : 1; - /// \brief True when there are no non-empty base classes. - /// + /// \brief True when any base class has any declared non-static data + /// members or bit-fields. /// This is a helper bit of state used to implement IsStandardLayout more /// efficiently. - unsigned HasNoNonEmptyBases : 1; + unsigned HasBasesWithFields : 1; /// \brief True when there are private non-static data members. unsigned HasPrivateFields : 1; @@ -695,6 +695,12 @@ /// deserializing the friends from an external AST source. FriendDecl *getFirstFriend() const; + /// Determine whether this class has an empty base class subobject of type X + /// or of one of the types that might be at offset 0 within X (per the C++ + /// "standard layout" rules). + bool hasSubobjectAtOffsetZeroOfEmptyBaseType(ASTContext &Ctx, + const CXXRecordDecl *X); + protected: CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, Index: cxx_dr_status.html =================================================================== --- cxx_dr_status.html +++ cxx_dr_status.html @@ -8365,7 +8365,7 @@ 1425 CD3 Base-class subobjects of standard-layout structs - Unknown + N/A (ABI constraint) 1426 @@ -9847,7 +9847,7 @@ 1672 CD4 Layout compatibility with multiple empty bases - Unknown + SVN 1673 @@ -10693,7 +10693,7 @@ 1813 CD4 Direct vs indirect bases in standard-layout classes - Unknown + SVN 1814 @@ -11101,7 +11101,7 @@ 1881 CD4 Standard-layout classes and unnamed bit-fields - Unknown + SVN 1882 @@ -12535,7 +12535,7 @@ 2120 CD4 Array as first non-static data member in standard-layout class - Unknown + SVN 2121 @@ -13189,7 +13189,7 @@ 2229 tentatively ready Volatile unnamed bit-fields - Unknown + SVN 2230 Index: make_cxx_dr_status =================================================================== --- make_cxx_dr_status +++ make_cxx_dr_status @@ -129,6 +129,9 @@ elif status == 'na lib': avail = 'N/A (Library DR)' avail_style = ' class="na"' + elif status == 'na abi': + avail = 'N/A (ABI constraint)' + avail_style = ' class="na"' elif status.startswith('sup '): dup = status.split(' ', 1)[1] avail = 'Superseded by %s' % (dup, dup)