DR1672, DR1813, DR1881, DR2120: Implement recent fixes to "standard
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 5 Apr 2018 18:55:37 +0000 (18:55 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 5 Apr 2018 18:55:37 +0000 (18:55 +0000)
layout" rules.

The new rules say that a standard-layout struct has its first non-static
data member and all base classes at offset 0, and consider a class to
not be standard-layout if that would result in multiple subobjects of a
single type having the same address.

We track "is C++11 standard-layout class" separately from "is
standard-layout class" so that the ABIs that need this information can
still use it.

Differential Revision: https://reviews.llvm.org/D45176

llvm-svn: 329332

17 files changed:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/DeclCXX.h
clang/include/clang/AST/Type.h
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/DeclCXX.cpp
clang/lib/AST/RecordLayoutBuilder.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/test/CXX/drs/dr14xx.cpp
clang/test/CXX/drs/dr16xx.cpp
clang/test/CXX/drs/dr18xx.cpp
clang/test/CXX/drs/dr21xx.cpp
clang/test/CXX/drs/dr22xx.cpp
clang/test/Layout/watchos-standard-layout.cpp [new file with mode: 0644]
clang/test/SemaCXX/type-traits.cpp
clang/www/cxx_dr_status.html
clang/www/make_cxx_dr_status

index f161e68..53ee651 100644 (file)
@@ -66,6 +66,11 @@ Non-comprehensive list of changes in this release
   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.
+
 - ...
 
 New Compiler Flags
index 7fd5729..5f5d3ba 100644 (file)
@@ -348,7 +348,12 @@ class CXXRecordDecl : public RecordDecl {
     /// one pure virtual function, (that can come from a base class).
     unsigned Abstract : 1;
 
-    /// \brief True when this class has standard layout.
+    /// \brief True when this class is standard-layout, per the applicable
+    /// language rules (including DRs).
+    unsigned IsStandardLayout : 1;
+
+    /// \brief True when this class was standard-layout under the C++11
+    /// definition.
     ///
     /// C++11 [class]p7.  A standard-layout class is a class that:
     /// * has no non-static data members of type non-standard-layout class (or
@@ -362,13 +367,19 @@ class CXXRecordDecl : public RecordDecl {
     ///   classes with non-static data members, and
     /// * has no base classes of the same type as the first non-static data
     ///   member.
-    unsigned IsStandardLayout : 1;
+    unsigned IsCXX11StandardLayout : 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 any base class has any declared non-static data
+    /// members.
+    /// This is a helper bit of state used to implement IsCXX11StandardLayout
+    /// more efficiently.
+    unsigned HasBasesWithNonStaticDataMembers : 1;
 
     /// \brief True when there are private non-static data members.
     unsigned HasPrivateFields : 1;
@@ -696,6 +707,12 @@ class CXXRecordDecl : public RecordDecl {
   /// 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,
@@ -1301,10 +1318,14 @@ public:
   /// not overridden.
   bool isAbstract() const { return data().Abstract; }
 
-  /// \brief Determine whether this class has standard layout per 
-  /// (C++ [class]p7)
+  /// \brief Determine whether this class is standard-layout per 
+  /// C++ [class]p7.
   bool isStandardLayout() const { return data().IsStandardLayout; }
 
+  /// \brief Determine whether this class was standard-layout per 
+  /// C++11 [class]p7, specifically using the C++11 rules without any DRs.
+  bool isCXX11StandardLayout() const { return data().IsCXX11StandardLayout; }
+
   /// \brief Determine whether this class, or any of its class subobjects,
   /// contains a mutable field.
   bool hasMutableFields() const { return data().HasMutableFields; }
index b5bb133..3d61b07 100644 (file)
@@ -798,7 +798,8 @@ public:
 
   /// Return true if this is a POD type according to the more relaxed rules
   /// of the C++11 standard, regardless of the current compilation's language.
-  /// (C++0x [basic.types]p9)
+  /// (C++0x [basic.types]p9). Note that, unlike
+  /// CXXRecordDecl::isCXX11StandardLayout, this takes DRs into account.
   bool isCXX11PODType(const ASTContext &Context) const;
 
   /// Return true if this is a trivial type per (C++0x [basic.types]p9)
index 2d9e1c8..98bde8b 100644 (file)
@@ -1071,7 +1071,10 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
     ToData.Polymorphic = FromData.Polymorphic;
     ToData.Abstract = FromData.Abstract;
     ToData.IsStandardLayout = FromData.IsStandardLayout;
-    ToData.HasNoNonEmptyBases = FromData.HasNoNonEmptyBases;
+    ToData.IsCXX11StandardLayout = FromData.IsCXX11StandardLayout;
+    ToData.HasBasesWithFields = FromData.HasBasesWithFields;
+    ToData.HasBasesWithNonStaticDataMembers =
+        FromData.HasBasesWithNonStaticDataMembers;
     ToData.HasPrivateFields = FromData.HasPrivateFields;
     ToData.HasProtectedFields = FromData.HasProtectedFields;
     ToData.HasPublicFields = FromData.HasPublicFields;
index 736b933..3cb1867 100644 (file)
@@ -74,7 +74,8 @@ void LazyASTUnresolvedSet::getFromExternalSource(ASTContext &C) const {
 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), IsCXX11StandardLayout(true),
+      HasBasesWithFields(false), HasBasesWithNonStaticDataMembers(false),
       HasPrivateFields(false), HasProtectedFields(false),
       HasPublicFields(false), HasMutableFields(false), HasVariantMembers(false),
       HasOnlyCMembers(true), HasInClassInitializer(false),
@@ -161,6 +162,25 @@ CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
   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<const CXXRecordDecl*, 8> SeenBaseTypes;
+  SmallVector<const CXXRecordDecl*, 8> 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) {
@@ -200,26 +220,37 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
     auto *BaseClassDecl =
         cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->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.
+    // 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 (BaseClassDecl->data().HasBasesWithFields ||
+        !BaseClassDecl->field_empty()) {
+      if (data().HasBasesWithFields)
+        // Two bases have members or bit-fields: not standard-layout.
         data().IsStandardLayout = false;
-      }
+      data().HasBasesWithFields = true;
+    }
+
+    // C++11 [class]p7:
+    //   A standard-layout class is a class that:
+    //     -- [...] has [...] at most one base class with non-static data
+    //        members
+    if (BaseClassDecl->data().HasBasesWithNonStaticDataMembers ||
+        BaseClassDecl->hasDirectFields()) {
+      if (data().HasBasesWithNonStaticDataMembers)
+        data().IsCXX11StandardLayout = false;
+      data().HasBasesWithNonStaticDataMembers = true;
+    }
 
+    if (!BaseClassDecl->isEmpty()) {
       // C++14 [meta.unary.prop]p4:
       //   T is a class type [...] with [...] no base class B for which
       //   is_empty<B>::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)
@@ -236,6 +267,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
     //    -- has no non-standard-layout base classes
     if (!BaseClassDecl->isStandardLayout())
       data().IsStandardLayout = false;
+    if (!BaseClassDecl->isCXX11StandardLayout())
+      data().IsCXX11StandardLayout = false;
 
     // Record if this base is the first non-literal field or base.
     if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType(C))
@@ -287,6 +320,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
       //   A standard-layout class is a class that: [...]
       //    -- has [...] no virtual base classes
       data().IsStandardLayout = false;
+      data().IsCXX11StandardLayout = false;
 
       // C++11 [dcl.constexpr]p4:
       //   In the definition of a constexpr constructor [...]
@@ -401,6 +435,16 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
 
     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 && hasRepeatedBaseClass(this))
+    data().IsStandardLayout = false;
   
   if (VBases.empty()) {
     data().IsParsingBaseSpecifiers = false;
@@ -501,6 +545,81 @@ void CXXRecordDecl::markedVirtualFunctionPure() {
   data().Abstract = true;
 }
 
+bool CXXRecordDecl::hasSubobjectAtOffsetZeroOfEmptyBaseType(
+    ASTContext &Ctx, const CXXRecordDecl *XFirst) {
+  if (!getNumBases())
+    return false;
+
+  llvm::SmallPtrSet<const CXXRecordDecl*, 8> Bases;
+  llvm::SmallPtrSet<const CXXRecordDecl*, 8> M;
+  SmallVector<const CXXRecordDecl*, 8> 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<FieldDecl>(D) &&
@@ -555,6 +674,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
       //   A standard-layout class is a class that: [...]
       //    -- has no virtual functions
       data().IsStandardLayout = false;
+      data().IsCXX11StandardLayout = false;
     }
   }
 
@@ -732,8 +852,18 @@ void CXXRecordDecl::addedMember(Decl *D) {
     return;
   }
 
+  ASTContext &Context = getASTContext();
+
   // Handle non-static data members.
   if (const auto *Field = dyn_cast<FieldDecl>(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)
+      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 
@@ -741,6 +871,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
     if (Field->isUnnamedBitfield())
       return;
     
+    // C++11 [class]p7:
+    //   A standard-layout class is a class that:
+    //    -- either has no non-static data members in the most derived class
+    //       [...] or has no base classes with non-static data members
+    if (data().HasBasesWithNonStaticDataMembers)
+      data().IsCXX11StandardLayout = false;
+
     // 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).
@@ -751,6 +888,11 @@ void CXXRecordDecl::addedMember(Decl *D) {
       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:
     //    [...]
@@ -762,8 +904,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
     case AS_none:       llvm_unreachable("Invalid access specifier");
     };
     if ((data().HasPrivateFields + data().HasProtectedFields +
-         data().HasPublicFields) > 1)
+         data().HasPublicFields) > 1) {
       data().IsStandardLayout = false;
+      data().IsCXX11StandardLayout = false;
+    }
 
     // Keep track of the presence of mutable fields.
     if (Field->isMutable()) {
@@ -784,7 +928,6 @@ void CXXRecordDecl::addedMember(Decl *D) {
     //
     // 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()) {
@@ -824,6 +967,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
       //   A standard-layout class is a class that:
       //    -- has no non-static data members of type [...] reference,
       data().IsStandardLayout = false;
+      data().IsCXX11StandardLayout = false;
 
       // C++1z [class.copy.ctor]p10:
       //   A defaulted copy constructor for a class X is defined as deleted if X has:
@@ -980,31 +1124,32 @@ void CXXRecordDecl::addedMember(Decl *D) {
         //       class (or array of such types) [...]
         if (!FieldRec->isStandardLayout())
           data().IsStandardLayout = false;
+        if (!FieldRec->isCXX11StandardLayout())
+          data().IsCXX11StandardLayout = false;
 
-        // C++0x [class]p7:
+        // C++2a [class]p7:
         //   A standard-layout class is a class that:
         //    [...]
+        //    -- has no element of the set M(S) of types as a base class.
+        if (data().IsStandardLayout && (isUnion() || IsFirstField) &&
+            hasSubobjectAtOffsetZeroOfEmptyBaseType(Context, FieldRec))
+          data().IsStandardLayout = false;
+
+        // C++11 [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) {
+        //       data member
+        if (data().IsCXX11StandardLayout && IsFirstField) {
+          // FIXME: We should check all base classes here, not just direct
+          // base classes.
           for (const auto &BI : bases()) {
             if (Context.hasSameUnqualifiedType(BI.getType(), T)) {
-              data().IsStandardLayout = false;
+              data().IsCXX11StandardLayout = false;
               break;
             }
           }
         }
-        
+
         // Keep track of the presence of mutable fields.
         if (FieldRec->hasMutableFields()) {
           data().HasMutableFields = true;
@@ -1067,17 +1212,6 @@ void CXXRecordDecl::addedMember(Decl *D) {
         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 e95bc91..390c8e0 100644 (file)
@@ -2134,7 +2134,7 @@ static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) {
     // mode; fortunately, that is true because we want to assign
     // consistently semantics to the type-traits intrinsics (or at
     // least as many of them as possible).
-    return RD->isTrivial() && RD->isStandardLayout();
+    return RD->isTrivial() && RD->isCXX11StandardLayout();
   }
 
   llvm_unreachable("bad tail-padding use kind");
index fa0db51..a6cc69d 100644 (file)
@@ -1563,7 +1563,9 @@ void ASTDeclReader::ReadCXXDefinitionData(
   Data.Polymorphic = Record.readInt();
   Data.Abstract = Record.readInt();
   Data.IsStandardLayout = Record.readInt();
-  Data.HasNoNonEmptyBases = Record.readInt();
+  Data.IsCXX11StandardLayout = Record.readInt();
+  Data.HasBasesWithFields = Record.readInt();
+  Data.HasBasesWithNonStaticDataMembers = Record.readInt();
   Data.HasPrivateFields = Record.readInt();
   Data.HasProtectedFields = Record.readInt();
   Data.HasPublicFields = Record.readInt();
@@ -1702,7 +1704,9 @@ void ASTDeclReader::MergeDefinitionData(
   MATCH_FIELD(Polymorphic)
   MATCH_FIELD(Abstract)
   MATCH_FIELD(IsStandardLayout)
-  MATCH_FIELD(HasNoNonEmptyBases)
+  MATCH_FIELD(IsCXX11StandardLayout)
+  MATCH_FIELD(HasBasesWithFields)
+  MATCH_FIELD(HasBasesWithNonStaticDataMembers)
   MATCH_FIELD(HasPrivateFields)
   MATCH_FIELD(HasProtectedFields)
   MATCH_FIELD(HasPublicFields)
index c2aabf5..317660e 100644 (file)
@@ -5995,7 +5995,9 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
   Record->push_back(Data.Polymorphic);
   Record->push_back(Data.Abstract);
   Record->push_back(Data.IsStandardLayout);
-  Record->push_back(Data.HasNoNonEmptyBases);
+  Record->push_back(Data.IsCXX11StandardLayout);
+  Record->push_back(Data.HasBasesWithFields);
+  Record->push_back(Data.HasBasesWithNonStaticDataMembers);
   Record->push_back(Data.HasPrivateFields);
   Record->push_back(Data.HasProtectedFields);
   Record->push_back(Data.HasPublicFields);
index 116437b..eb5ba3d 100644 (file)
@@ -7,6 +7,8 @@
 // expected-no-diagnostics
 #endif
 
+// dr1425: na abi
+
 namespace dr1460 { // dr1460: 3.5
 #if __cplusplus >= 201103L
   namespace DRExample {
index 08ae925..898672a 100644 (file)
@@ -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 @@ namespace dr1658 { // dr1658: 5
 
   // 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<typename T> struct Y : X, A { T t; };
+
+  static_assert(!__is_standard_layout(Y<E>), "");
+  static_assert(__is_standard_layout(Y<F>), "");
+  static_assert(!__is_standard_layout(Y<G>), "");
+  static_assert(!__is_standard_layout(Y<H>), "");
+  static_assert(!__is_standard_layout(Y<X>), "");
+}
index e4ec199..a0f470e 100644 (file)
@@ -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 78fc0be..2522ff7 100644 (file)
@@ -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 55b3d78..021707d 100644 (file)
@@ -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}}
diff --git a/clang/test/Layout/watchos-standard-layout.cpp b/clang/test/Layout/watchos-standard-layout.cpp
new file mode 100644 (file)
index 0000000..bd7bb1a
--- /dev/null
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fsyntax-only -triple armv7k-apple-darwin-watchos -fdump-record-layouts %s | FileCheck %s
+
+// WatchOS, 64-bit iOS, and WebAssembly use the C++11 definition of POD to
+// determine whether we can reuse the tail padding of a struct (POD is
+// "trivially copyable and standard layout"). The definition of standard
+// layout changed some time around C++17; check that we still use the old
+// ABI rule.
+
+// B is not standard-layout, but it was under C++11's rule, so we pack
+// C::d into its tail padding anyway.
+struct A { int : 0; };
+struct B : A { int n; char c[3]; };
+struct C : B { char d; };
+int c = sizeof(C);
+static_assert(!__is_standard_layout(B));
+
+// 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:- |       int 
+// CHECK-NEXT:     0 |     int n
+// CHECK-NEXT:     4 |     char [3] c
+// CHECK-NEXT:     8 |   char d
+// CHECK-NEXT:       | [sizeof=12, dsize=9, align=4,
+// CHECK-NEXT:       |  nvsize=9, nvalign=4]
+
+// F is not standard-layout due to the repeated D base class, but it was under
+// C++11's rule, so we pack G::d into its tail padding anyway.
+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);
+static_assert(!__is_standard_layout(F));
+
+// 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-NEXT:     8 |   char d
+// CHECK-NEXT:       | [sizeof=12, dsize=9, align=4,
+// CHECK-NEXT:       |  nvsize=9, nvalign=4]
index ca96503..3370468 100644 (file)
@@ -1353,6 +1353,59 @@ void is_standard_layout()
   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 c5a8ac8..4d9a726 100644 (file)
@@ -8365,7 +8365,7 @@ and <I>POD class</I></td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1425">1425</a></td>
     <td>CD3</td>
     <td>Base-class subobjects of standard-layout structs</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="na" align="center">N/A (ABI constraint)</td>
   </tr>
   <tr class="open" id="1426">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1426">1426</a></td>
@@ -9847,7 +9847,7 @@ and <I>POD class</I></td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1672">1672</a></td>
     <td>CD4</td>
     <td>Layout compatibility with multiple empty bases</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="svn" align="center">SVN</td>
   </tr>
   <tr id="1673">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1673">1673</a></td>
@@ -10693,7 +10693,7 @@ and <I>POD class</I></td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1813">1813</a></td>
     <td>CD4</td>
     <td>Direct vs indirect bases in standard-layout classes</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="svn" align="center">SVN</td>
   </tr>
   <tr id="1814">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1814">1814</a></td>
@@ -11101,7 +11101,7 @@ and <I>POD class</I></td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1881">1881</a></td>
     <td>CD4</td>
     <td>Standard-layout classes and unnamed bit-fields</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="svn" align="center">SVN</td>
   </tr>
   <tr id="1882">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1882">1882</a></td>
@@ -12535,7 +12535,7 @@ and <I>POD class</I></td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2120">2120</a></td>
     <td>CD4</td>
     <td>Array as first non-static data member in standard-layout class</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="svn" align="center">SVN</td>
   </tr>
   <tr class="open" id="2121">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2121">2121</a></td>
@@ -13189,7 +13189,7 @@ and <I>POD class</I></td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2229">2229</a></td>
     <td>tentatively ready</td>
     <td>Volatile unnamed bit-fields</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="svn" align="center">SVN</td>
   </tr>
   <tr id="2230">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2230">2230</a></td>
index 3b0e09d..5b19917 100755 (executable)
@@ -129,6 +129,9 @@ def availability(issue):
   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 <a href="#%s">%s</a>' % (dup, dup)