r363976 - P0840R2: support for [[no_unique_address]] attribute

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 20 13:44:45 PDT 2019


Author: rsmith
Date: Thu Jun 20 13:44:45 2019
New Revision: 363976

URL: http://llvm.org/viewvc/llvm-project?rev=363976&view=rev
Log:
P0840R2: support for [[no_unique_address]] attribute

Summary:
Add support for the C++2a [[no_unique_address]] attribute for targets using the Itanium C++ ABI.

This depends on D63371.

Reviewers: rjmccall, aaron.ballman

Subscribers: dschuff, aheejin, cfe-commits

Tags: #clang

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

Added:
    cfe/trunk/test/CodeGenCXX/no-unique-address.cpp
    cfe/trunk/test/Layout/no-unique-address.cpp
    cfe/trunk/test/SemaCXX/cxx2a-no-unique-address.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/AttrDocs.td
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/CGExprAgg.cpp
    cfe/trunk/lib/CodeGen/CGExprConstant.cpp
    cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp
    cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/test/CodeGenCXX/tail-padding.cpp
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Thu Jun 20 13:44:45 2019
@@ -2729,6 +2729,11 @@ public:
   /// bit-fields.
   bool isZeroLengthBitField(const ASTContext &Ctx) const;
 
+  /// Determine if this field is a subobject of zero size, that is, either a
+  /// zero-length bit-field or a field of empty class type with the
+  /// [[no_unique_address]] attribute.
+  bool isZeroSize(const ASTContext &Ctx) const;
+
   /// Get the kind of (C++11) default member initializer that this field has.
   InClassInitStyle getInClassInitStyle() const {
     InitStorageKind storageKind = InitStorage.getInt();

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Thu Jun 20 13:44:45 2019
@@ -334,10 +334,12 @@ class CXXRecordDecl : public RecordDecl
     /// True when this class is a POD-type.
     unsigned PlainOldData : 1;
 
-    /// true when this class is empty for traits purposes,
-    /// i.e. has no data members other than 0-width bit-fields, has no
-    /// virtual function/base, and doesn't inherit from a non-empty
-    /// class. Doesn't take union-ness into account.
+    /// True when this class is empty for traits purposes, that is:
+    ///  * has no data members other than 0-width bit-fields and empty fields
+    ///    marked [[no_unique_address]]
+    ///  * has no virtual function/base, and
+    ///  * doesn't inherit from a non-empty class.
+    /// Doesn't take union-ness into account.
     unsigned Empty : 1;
 
     /// True when this class is polymorphic, i.e., has at

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Thu Jun 20 13:44:45 2019
@@ -14,6 +14,7 @@ class DocumentationCategory<string name>
 }
 def DocCatFunction : DocumentationCategory<"Function Attributes">;
 def DocCatVariable : DocumentationCategory<"Variable Attributes">;
+def DocCatField : DocumentationCategory<"Field Attributes">;
 def DocCatType : DocumentationCategory<"Type Attributes">;
 def DocCatStmt : DocumentationCategory<"Statement Attributes">;
 def DocCatDecl : DocumentationCategory<"Declaration Attributes">;
@@ -315,12 +316,14 @@ class TargetSpec {
   // Specifies Operating Systems for which the target applies, based off the
   // OSType enumeration in Triple.h
   list<string> OSes;
-  // Specifies the C++ ABIs for which the target applies, based off the
-  // TargetCXXABI::Kind in TargetCXXABI.h.
-  list<string> CXXABIs;
   // Specifies Object Formats for which the target applies, based off the
   // ObjectFormatType enumeration in Triple.h
   list<string> ObjectFormats;
+  // A custom predicate, written as an expression evaluated in a context
+  // with the following declarations in scope:
+  //   const clang::TargetInfo &Target;
+  //   const llvm::Triple &T = Target.getTriple();
+  code CustomCode = [{}];
 }
 
 class TargetArch<list<string> arches> : TargetSpec {
@@ -338,8 +341,11 @@ def TargetWebAssembly : TargetArch<["was
 def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch64"]> {
   let OSes = ["Win32"];
 }
+def TargetItaniumCXXABI : TargetSpec {
+  let CustomCode = [{ Target.getCXXABI().isItaniumFamily() }];
+}
 def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch64"]> {
-  let CXXABIs = ["Microsoft"];
+  let CustomCode = [{ Target.getCXXABI().isMicrosoft() }];
 }
 def TargetELF : TargetSpec {
   let ObjectFormats = ["ELF"];
@@ -1408,6 +1414,12 @@ def NeonVectorType : TypeAttr {
   let ASTNode = 0;
 }
 
+def NoUniqueAddress : InheritableAttr, TargetSpecificAttr<TargetItaniumCXXABI> {
+  let Spellings = [CXX11<"", "no_unique_address", 201803>];
+  let Subjects = SubjectList<[NonBitField], ErrorDiag>;
+  let Documentation = [NoUniqueAddressDocs];
+}
+
 def ReturnsTwice : InheritableAttr {
   let Spellings = [GCC<"returns_twice">];
   let Subjects = SubjectList<[Function]>;

Modified: cfe/trunk/include/clang/Basic/AttrDocs.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/AttrDocs.td (original)
+++ cfe/trunk/include/clang/Basic/AttrDocs.td Thu Jun 20 13:44:45 2019
@@ -1009,6 +1009,32 @@ is not specified.
   }];
 }
 
+def NoUniqueAddressDocs : Documentation {
+  let Category = DocCatField;
+  let Content = [{
+The ``no_unique_address`` attribute allows tail padding in a non-static data
+member to overlap other members of the enclosing class (and in the special
+case when the type is empty, permits it to fully overlap other members).
+The field is laid out as if a base class were encountered at the corresponding
+point within the class (except that it does not share a vptr with the enclosing
+object).
+
+Example usage:
+
+.. code-block:: c++
+
+  template<typename T, typename Alloc> struct my_vector {
+    T *p;
+    [[no_unique_address]] Alloc alloc;
+    // ...
+  };
+  static_assert(sizeof(my_vector<int, std::allocator<int>>) == sizeof(int*));
+
+``[[no_unique_address]]`` is a standard C++20 attribute. Clang supports its use
+in C++11 onwards.
+  }];
+}
+
 def ObjCRequiresSuperDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Jun 20 13:44:45 2019
@@ -3913,6 +3913,39 @@ bool FieldDecl::isZeroLengthBitField(con
          getBitWidthValue(Ctx) == 0;
 }
 
+bool FieldDecl::isZeroSize(const ASTContext &Ctx) const {
+  if (isZeroLengthBitField(Ctx))
+    return true;
+
+  // C++2a [intro.object]p7:
+  //   An object has nonzero size if it
+  //     -- is not a potentially-overlapping subobject, or
+  if (!hasAttr<NoUniqueAddressAttr>())
+    return false;
+
+  //     -- is not of class type, or
+  const auto *RT = getType()->getAs<RecordType>();
+  if (!RT)
+    return false;
+  const RecordDecl *RD = RT->getDecl()->getDefinition();
+  if (!RD) {
+    assert(isInvalidDecl() && "valid field has incomplete type");
+    return false;
+  }
+
+  //     -- [has] virtual member functions or virtual base classes, or
+  //     -- has subobjects of nonzero size or bit-fields of nonzero length
+  const auto *CXXRD = cast<CXXRecordDecl>(RD);
+  if (!CXXRD->isEmpty())
+    return false;
+
+  // Otherwise, [...] the circumstances under which the object has zero size
+  // are implementation-defined.
+  // FIXME: This might be Itanium ABI specific; we don't yet know what the MS
+  // ABI will do.
+  return true;
+}
+
 unsigned FieldDecl::getFieldIndex() const {
   const FieldDecl *Canonical = getCanonicalDecl();
   if (Canonical != this)

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Jun 20 13:44:45 2019
@@ -605,14 +605,19 @@ bool CXXRecordDecl::hasSubobjectAtOffset
     // 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
+    //      [recurse to each field] that is either of zero size or is the
+    //      first non-static data member of X
     //   -- If X is a union type, [recurse to union members]
+    bool IsFirstField = true;
     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 (!IsFirstField && !FD->isZeroSize(Ctx))
+        continue;
+
       //   -- If X is n array type, [visit the element type]
       QualType T = Ctx.getBaseElementType(FD->getType());
       if (auto *RD = T->getAsCXXRecordDecl())
@@ -620,7 +625,7 @@ bool CXXRecordDecl::hasSubobjectAtOffset
           return true;
 
       if (!X->isUnion())
-        break;
+        IsFirstField = false;
     }
   }
 
@@ -1068,6 +1073,10 @@ void CXXRecordDecl::addedMember(Decl *D)
     if (T->isReferenceType())
       data().DefaultedMoveAssignmentIsDeleted = true;
 
+    // Bitfields of length 0 are also zero-sized, but we already bailed out for
+    // those because they are always unnamed.
+    bool IsZeroSize = Field->isZeroSize(Context);
+
     if (const auto *RecordTy = T->getAs<RecordType>()) {
       auto *FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
       if (FieldRec->getDefinition()) {
@@ -1183,7 +1192,8 @@ void CXXRecordDecl::addedMember(Decl *D)
         //   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) &&
+        if (data().IsStandardLayout &&
+            (isUnion() || IsFirstField || IsZeroSize) &&
             hasSubobjectAtOffsetZeroOfEmptyBaseType(Context, FieldRec))
           data().IsStandardLayout = false;
 
@@ -1265,8 +1275,10 @@ void CXXRecordDecl::addedMember(Decl *D)
     }
 
     // C++14 [meta.unary.prop]p4:
-    //   T is a class type [...] with [...] no non-static data members
-    data().Empty = false;
+    //   T is a class type [...] with [...] no non-static data members other
+    //   than subobjects of zero size
+    if (data().Empty && !IsZeroSize)
+      data().Empty = false;
   }
 
   // Handle using declarations of conversion functions.

Modified: cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RecordLayoutBuilder.cpp?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/lib/AST/RecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/AST/RecordLayoutBuilder.cpp Thu Jun 20 13:44:45 2019
@@ -127,9 +127,10 @@ class EmptySubobjectMap {
                                  CharUnits Offset, bool PlacingEmptyBase);
 
   void UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
-                                  const CXXRecordDecl *Class,
-                                  CharUnits Offset);
-  void UpdateEmptyFieldSubobjects(const FieldDecl *FD, CharUnits Offset);
+                                  const CXXRecordDecl *Class, CharUnits Offset,
+                                  bool PlacingOverlappingField);
+  void UpdateEmptyFieldSubobjects(const FieldDecl *FD, CharUnits Offset,
+                                  bool PlacingOverlappingField);
 
   /// AnyEmptySubobjectsBeyondOffset - Returns whether there are any empty
   /// subobjects beyond the given offset.
@@ -351,7 +352,7 @@ void EmptySubobjectMap::UpdateEmptyBaseS
       continue;
 
     CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
-    UpdateEmptyFieldSubobjects(*I, FieldOffset);
+    UpdateEmptyFieldSubobjects(*I, FieldOffset, PlacingEmptyBase);
   }
 }
 
@@ -471,20 +472,25 @@ EmptySubobjectMap::CanPlaceFieldAtOffset
     return false;
 
   // We are able to place the member variable at this offset.
-  // Make sure to update the empty base subobject map.
-  UpdateEmptyFieldSubobjects(FD, Offset);
+  // Make sure to update the empty field subobject map.
+  UpdateEmptyFieldSubobjects(FD, Offset, FD->hasAttr<NoUniqueAddressAttr>());
   return true;
 }
 
-void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
-                                                   const CXXRecordDecl *Class,
-                                                   CharUnits Offset) {
+void EmptySubobjectMap::UpdateEmptyFieldSubobjects(
+    const CXXRecordDecl *RD, const CXXRecordDecl *Class, CharUnits Offset,
+    bool PlacingOverlappingField) {
   // We know that the only empty subobjects that can conflict with empty
-  // field subobjects are subobjects of empty bases that can be placed at offset
-  // zero. Because of this, we only need to keep track of empty field
-  // subobjects with offsets less than the size of the largest empty
-  // subobject for our class.
-  if (Offset >= SizeOfLargestEmptySubobject)
+  // field subobjects are subobjects of empty bases and potentially-overlapping
+  // fields that can be placed at offset zero. Because of this, we only need to
+  // keep track of empty field subobjects with offsets less than the size of
+  // the largest empty subobject for our class.
+  //
+  // (Proof: we will only consider placing a subobject at offset zero or at
+  // >= the current dsize. The only cases where the earlier subobject can be
+  // placed beyond the end of dsize is if it's an empty base or a
+  // potentially-overlapping field.)
+  if (!PlacingOverlappingField && Offset >= SizeOfLargestEmptySubobject)
     return;
 
   AddSubobjectAtOffset(RD, Offset);
@@ -499,7 +505,8 @@ void EmptySubobjectMap::UpdateEmptyField
     const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
 
     CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
-    UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset);
+    UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset,
+                               PlacingOverlappingField);
   }
 
   if (RD == Class) {
@@ -508,7 +515,8 @@ void EmptySubobjectMap::UpdateEmptyField
       const CXXRecordDecl *VBaseDecl = Base.getType()->getAsCXXRecordDecl();
 
       CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
-      UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset);
+      UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset,
+                                 PlacingOverlappingField);
     }
   }
 
@@ -521,15 +529,15 @@ void EmptySubobjectMap::UpdateEmptyField
 
     CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
 
-    UpdateEmptyFieldSubobjects(*I, FieldOffset);
+    UpdateEmptyFieldSubobjects(*I, FieldOffset, PlacingOverlappingField);
   }
 }
 
-void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD,
-                                                   CharUnits Offset) {
+void EmptySubobjectMap::UpdateEmptyFieldSubobjects(
+    const FieldDecl *FD, CharUnits Offset, bool PlacingOverlappingField) {
   QualType T = FD->getType();
   if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
-    UpdateEmptyFieldSubobjects(RD, RD, Offset);
+    UpdateEmptyFieldSubobjects(RD, RD, Offset, PlacingOverlappingField);
     return;
   }
 
@@ -552,10 +560,12 @@ void EmptySubobjectMap::UpdateEmptyField
       // offset zero. Because of this, we only need to keep track of empty field
       // subobjects with offsets less than the size of the largest empty
       // subobject for our class.
-      if (ElementOffset >= SizeOfLargestEmptySubobject)
+      if (!PlacingOverlappingField &&
+          ElementOffset >= SizeOfLargestEmptySubobject)
         return;
 
-      UpdateEmptyFieldSubobjects(RD, RD, ElementOffset);
+      UpdateEmptyFieldSubobjects(RD, RD, ElementOffset,
+                                 PlacingOverlappingField);
       ElementOffset += Layout.getSize();
     }
   }
@@ -622,6 +632,10 @@ protected:
   CharUnits NonVirtualSize;
   CharUnits NonVirtualAlignment;
 
+  /// If we've laid out a field but not included its tail padding in Size yet,
+  /// this is the size up to the end of that field.
+  CharUnits PaddedFieldSize;
+
   /// PrimaryBase - the primary base class (if one exists) of the class
   /// we're laying out.
   const CXXRecordDecl *PrimaryBase;
@@ -670,7 +684,8 @@ protected:
         UnfilledBitsInLastUnit(0), LastBitfieldTypeSize(0),
         MaxFieldAlignment(CharUnits::Zero()), DataSize(0),
         NonVirtualSize(CharUnits::Zero()),
-        NonVirtualAlignment(CharUnits::One()), PrimaryBase(nullptr),
+        NonVirtualAlignment(CharUnits::One()),
+        PaddedFieldSize(CharUnits::Zero()), PrimaryBase(nullptr),
         PrimaryBaseIsVirtual(false), HasOwnVFPtr(false),
         HasPackedField(false), FirstNearlyEmptyVBase(nullptr) {}
 
@@ -980,7 +995,6 @@ void ItaniumRecordLayoutBuilder::EnsureV
 
   // Round up the current record size to pointer alignment.
   setSize(getSize().alignTo(BaseAlign));
-  setDataSize(getSize());
 
   // Update the alignment.
   UpdateAlignment(BaseAlign, UnpackedBaseAlign);
@@ -1172,6 +1186,7 @@ ItaniumRecordLayoutBuilder::LayoutBase(c
   // Query the external layout to see if it provides an offset.
   bool HasExternalLayout = false;
   if (UseExternalLayout) {
+    // FIXME: This appears to be reversed.
     if (Base->IsVirtual)
       HasExternalLayout = External.getExternalNVBaseOffset(Base->Class, Offset);
     else
@@ -1342,8 +1357,8 @@ void ItaniumRecordLayoutBuilder::Layout(
 
     // We start laying out ivars not at the end of the superclass
     // structure, but at the next byte following the last field.
-    setSize(SL.getDataSize());
-    setDataSize(getSize());
+    setDataSize(SL.getDataSize());
+    setSize(getDataSize());
   }
 
   InitializeLayout(D);
@@ -1729,32 +1744,49 @@ void ItaniumRecordLayoutBuilder::LayoutF
   UnfilledBitsInLastUnit = 0;
   LastBitfieldTypeSize = 0;
 
+  auto *FieldClass = D->getType()->getAsCXXRecordDecl();
+  bool PotentiallyOverlapping = D->hasAttr<NoUniqueAddressAttr>() && FieldClass;
+  bool IsOverlappingEmptyField = PotentiallyOverlapping && FieldClass->isEmpty();
   bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
-  CharUnits FieldOffset =
-    IsUnion ? CharUnits::Zero() : getDataSize();
+
+  CharUnits FieldOffset = (IsUnion || IsOverlappingEmptyField)
+                              ? CharUnits::Zero()
+                              : getDataSize();
   CharUnits FieldSize;
   CharUnits FieldAlign;
+  // The amount of this class's dsize occupied by the field.
+  // This is equal to FieldSize unless we're permitted to pack
+  // into the field's tail padding.
+  CharUnits EffectiveFieldSize;
 
   if (D->getType()->isIncompleteArrayType()) {
     // This is a flexible array member; we can't directly
     // query getTypeInfo about these, so we figure it out here.
     // Flexible array members don't have any size, but they
     // have to be aligned appropriately for their element type.
-    FieldSize = CharUnits::Zero();
+    EffectiveFieldSize = FieldSize = CharUnits::Zero();
     const ArrayType* ATy = Context.getAsArrayType(D->getType());
     FieldAlign = Context.getTypeAlignInChars(ATy->getElementType());
   } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
     unsigned AS = Context.getTargetAddressSpace(RT->getPointeeType());
-    FieldSize =
+    EffectiveFieldSize = FieldSize =
       Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(AS));
     FieldAlign =
       Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(AS));
   } else {
     std::pair<CharUnits, CharUnits> FieldInfo =
       Context.getTypeInfoInChars(D->getType());
-    FieldSize = FieldInfo.first;
+    EffectiveFieldSize = FieldSize = FieldInfo.first;
     FieldAlign = FieldInfo.second;
 
+    // A potentially-overlapping field occupies its dsize or nvsize, whichever
+    // is larger.
+    if (PotentiallyOverlapping) {
+      const ASTRecordLayout &Layout = Context.getASTRecordLayout(FieldClass);
+      EffectiveFieldSize =
+          std::max(Layout.getNonVirtualSize(), Layout.getDataSize());
+    }
+
     if (IsMsStruct) {
       // If MS bitfield layout is required, figure out what type is being
       // laid out and align the field to the width of that type.
@@ -1834,7 +1866,12 @@ void ItaniumRecordLayoutBuilder::LayoutF
       // Check if we can place the field at this offset.
       while (!EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset)) {
         // We couldn't place the field at the offset. Try again at a new offset.
-        FieldOffset += FieldAlign;
+        // We try offset 0 (for an empty field) and then dsize(C) onwards.
+        if (FieldOffset == CharUnits::Zero() &&
+            getDataSize() != CharUnits::Zero())
+          FieldOffset = getDataSize().alignTo(FieldAlign);
+        else
+          FieldOffset += FieldAlign;
       }
     }
   }
@@ -1853,18 +1890,23 @@ void ItaniumRecordLayoutBuilder::LayoutF
     if (FieldSize % ASanAlignment)
       ExtraSizeForAsan +=
           ASanAlignment - CharUnits::fromQuantity(FieldSize % ASanAlignment);
-    FieldSize += ExtraSizeForAsan;
+    EffectiveFieldSize = FieldSize = FieldSize + ExtraSizeForAsan;
   }
 
   // Reserve space for this field.
-  uint64_t FieldSizeInBits = Context.toBits(FieldSize);
-  if (IsUnion)
-    setDataSize(std::max(getDataSizeInBits(), FieldSizeInBits));
-  else
-    setDataSize(FieldOffset + FieldSize);
+  if (!IsOverlappingEmptyField) {
+    uint64_t EffectiveFieldSizeInBits = Context.toBits(EffectiveFieldSize);
+    if (IsUnion)
+      setDataSize(std::max(getDataSizeInBits(), EffectiveFieldSizeInBits));
+    else
+      setDataSize(FieldOffset + EffectiveFieldSize);
 
-  // Update the size.
-  setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+    PaddedFieldSize = std::max(PaddedFieldSize, FieldOffset + FieldSize);
+    setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+  } else {
+    setSize(std::max(getSizeInBits(),
+                     (uint64_t)Context.toBits(FieldOffset + FieldSize)));
+  }
 
   // Remember max struct/class alignment.
   UnadjustedAlignment = std::max(UnadjustedAlignment, FieldAlign);
@@ -1885,6 +1927,10 @@ void ItaniumRecordLayoutBuilder::FinishL
       setSize(CharUnits::One());
   }
 
+  // If we have any remaining field tail padding, include that in the overall
+  // size.
+  setSize(std::max(getSizeInBits(), (uint64_t)Context.toBits(PaddedFieldSize)));
+
   // Finally, round the size of the record up to the alignment of the
   // record itself.
   uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastUnit;

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Thu Jun 20 13:44:45 2019
@@ -3879,12 +3879,27 @@ LValue CodeGenFunction::EmitLValueForLam
   return EmitLValueForField(LambdaLV, Field);
 }
 
+/// Get the address of a zero-sized field within a record. The resulting
+/// address doesn't necessarily have the right type.
+static Address emitAddrOfZeroSizeField(CodeGenFunction &CGF, Address Base,
+                                       const FieldDecl *Field) {
+  CharUnits Offset = CGF.getContext().toCharUnitsFromBits(
+      CGF.getContext().getFieldOffset(Field));
+  if (Offset.isZero())
+    return Base;
+  Base = CGF.Builder.CreateElementBitCast(Base, CGF.Int8Ty);
+  return CGF.Builder.CreateConstInBoundsByteGEP(Base, Offset);
+}
+
 /// Drill down to the storage of a field without walking into
 /// reference types.
 ///
 /// The resulting address doesn't necessarily have the right type.
 static Address emitAddrOfFieldStorage(CodeGenFunction &CGF, Address base,
                                       const FieldDecl *field) {
+  if (field->isZeroSize(CGF.getContext()))
+    return emitAddrOfZeroSizeField(CGF, base, field);
+
   const RecordDecl *rec = field->getParent();
 
   unsigned idx =

Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Thu Jun 20 13:44:45 2019
@@ -1846,15 +1846,32 @@ LValue CodeGenFunction::EmitAggExprToLVa
   return LV;
 }
 
+AggValueSlot::Overlap_t
+CodeGenFunction::overlapForFieldInit(const FieldDecl *FD) {
+  if (!FD->hasAttr<NoUniqueAddressAttr>() || !FD->getType()->isRecordType())
+    return AggValueSlot::DoesNotOverlap;
+
+  // If the field lies entirely within the enclosing class's nvsize, its tail
+  // padding cannot overlap any already-initialized object. (The only subobjects
+  // with greater addresses that might already be initialized are vbases.)
+  const RecordDecl *ClassRD = FD->getParent();
+  const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassRD);
+  if (Layout.getFieldOffset(FD->getFieldIndex()) +
+          getContext().getTypeSize(FD->getType()) <=
+      (uint64_t)getContext().toBits(Layout.getNonVirtualSize()))
+    return AggValueSlot::DoesNotOverlap;
+
+  // The tail padding may contain values we need to preserve.
+  return AggValueSlot::MayOverlap;
+}
+
 AggValueSlot::Overlap_t CodeGenFunction::overlapForBaseInit(
     const CXXRecordDecl *RD, const CXXRecordDecl *BaseRD, bool IsVirtual) {
-  // Virtual bases are initialized first, in address order, so there's never
-  // any overlap during their initialization.
-  //
-  // FIXME: Under P0840, this is no longer true: the tail padding of a vbase
-  // of a field could be reused by a vbase of a containing class.
+  // If the most-derived object is a field declared with [[no_unique_address]],
+  // the tail padding of any virtual base could be reused for other subobjects
+  // of that field's class.
   if (IsVirtual)
-    return AggValueSlot::DoesNotOverlap;
+    return AggValueSlot::MayOverlap;
 
   // If the base class is laid out entirely within the nvsize of the derived
   // class, its tail padding cannot yet be initialized, so we can issue

Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Thu Jun 20 13:44:45 2019
@@ -675,11 +675,12 @@ bool ConstStructBuilder::Build(InitListE
     ++FieldNo;
 
     // If this is a union, skip all the fields that aren't being initialized.
-    if (RD->isUnion() && ILE->getInitializedFieldInUnion() != Field)
+    if (RD->isUnion() &&
+        !declaresSameEntity(ILE->getInitializedFieldInUnion(), Field))
       continue;
 
-    // Don't emit anonymous bitfields, they just affect layout.
-    if (Field->isUnnamedBitfield())
+    // Don't emit anonymous bitfields or zero-sized fields.
+    if (Field->isUnnamedBitfield() || Field->isZeroSize(CGM.getContext()))
       continue;
 
     // Get the initializer.  A struct can include fields without initializers,
@@ -720,6 +721,10 @@ bool ConstStructBuilder::Build(InitListE
       if (!AppendField(Field, Layout.getFieldOffset(FieldNo), EltInit,
                        AllowOverwrite))
         return false;
+      // After emitting a non-empty field with [[no_unique_address]], we may
+      // need to overwrite its tail padding.
+      if (Field->hasAttr<NoUniqueAddressAttr>())
+        AllowOverwrite = true;
     } else {
       // Otherwise we have a bitfield.
       if (auto *CI = dyn_cast<llvm::ConstantInt>(EltInit)) {
@@ -793,14 +798,15 @@ bool ConstStructBuilder::Build(const APV
   unsigned FieldNo = 0;
   uint64_t OffsetBits = CGM.getContext().toBits(Offset);
 
+  bool AllowOverwrite = false;
   for (RecordDecl::field_iterator Field = RD->field_begin(),
        FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
     // If this is a union, skip all the fields that aren't being initialized.
     if (RD->isUnion() && !declaresSameEntity(Val.getUnionField(), *Field))
       continue;
 
-    // Don't emit anonymous bitfields, they just affect layout.
-    if (Field->isUnnamedBitfield())
+    // Don't emit anonymous bitfields or zero-sized fields.
+    if (Field->isUnnamedBitfield() || Field->isZeroSize(CGM.getContext()))
       continue;
 
     // Emit the value of the initializer.
@@ -814,12 +820,16 @@ bool ConstStructBuilder::Build(const APV
     if (!Field->isBitField()) {
       // Handle non-bitfield members.
       if (!AppendField(*Field, Layout.getFieldOffset(FieldNo) + OffsetBits,
-                       EltInit))
+                       EltInit, AllowOverwrite))
         return false;
+      // After emitting a non-empty field with [[no_unique_address]], we may
+      // need to overwrite its tail padding.
+      if (Field->hasAttr<NoUniqueAddressAttr>())
+        AllowOverwrite = true;
     } else {
       // Otherwise we have a bitfield.
       if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo) + OffsetBits,
-                          cast<llvm::ConstantInt>(EltInit)))
+                          cast<llvm::ConstantInt>(EltInit), AllowOverwrite))
         return false;
     }
   }
@@ -2216,7 +2226,7 @@ static llvm::Constant *EmitNullConstant(
   for (const auto *Field : record->fields()) {
     // Fill in non-bitfields. (Bitfields always use a zero pattern, which we
     // will fill in later.)
-    if (!Field->isBitField()) {
+    if (!Field->isBitField() && !Field->isZeroSize(CGM.getContext())) {
       unsigned fieldIndex = layout.getLLVMFieldNo(Field);
       elements[fieldIndex] = CGM.EmitNullConstant(Field->getType());
     }

Modified: cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp Thu Jun 20 13:44:45 2019
@@ -7811,7 +7811,7 @@ private:
     for (const auto *Field : RD->fields()) {
       // Fill in non-bitfields. (Bitfields always use a zero pattern, which we
       // will fill in later.)
-      if (!Field->isBitField()) {
+      if (!Field->isBitField() && !Field->isZeroSize(CGF.getContext())) {
         unsigned FieldIndex = RL.getLLVMFieldNo(Field);
         RecordLayout[FieldIndex] = Field;
       }

Modified: cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp Thu Jun 20 13:44:45 2019
@@ -347,18 +347,21 @@ void CGRecordLowering::lowerUnion() {
 void CGRecordLowering::accumulateFields() {
   for (RecordDecl::field_iterator Field = D->field_begin(),
                                   FieldEnd = D->field_end();
-    Field != FieldEnd;)
+    Field != FieldEnd;) {
     if (Field->isBitField()) {
       RecordDecl::field_iterator Start = Field;
       // Iterate to gather the list of bitfields.
       for (++Field; Field != FieldEnd && Field->isBitField(); ++Field);
       accumulateBitFields(Start, Field);
-    } else {
+    } else if (!Field->isZeroSize(Context)) {
       Members.push_back(MemberInfo(
           bitsToCharUnits(getFieldBitOffset(*Field)), MemberInfo::Field,
           getStorageType(*Field), *Field));
       ++Field;
+    } else {
+      ++Field;
     }
+  }
 }
 
 void
@@ -590,10 +593,17 @@ void CGRecordLowering::clipTailPadding()
     if (!Member->Data && Member->Kind != MemberInfo::Scissor)
       continue;
     if (Member->Offset < Tail) {
-      assert(Prior->Kind == MemberInfo::Field && !Prior->FD &&
+      assert(Prior->Kind == MemberInfo::Field &&
              "Only storage fields have tail padding!");
-      Prior->Data = getByteArrayType(bitsToCharUnits(llvm::alignTo(
-          cast<llvm::IntegerType>(Prior->Data)->getIntegerBitWidth(), 8)));
+      if (!Prior->FD || Prior->FD->isBitField())
+        Prior->Data = getByteArrayType(bitsToCharUnits(llvm::alignTo(
+            cast<llvm::IntegerType>(Prior->Data)->getIntegerBitWidth(), 8)));
+      else {
+        assert(Prior->FD->hasAttr<NoUniqueAddressAttr>() &&
+               "should not have reused this field's tail padding");
+        Prior->Data = getByteArrayType(
+            Context.getTypeInfoDataSizeInChars(Prior->FD->getType()).first);
+      }
     }
     if (Member->Data)
       Prior = Member;
@@ -797,6 +807,10 @@ CGRecordLayout *CodeGenTypes::ComputeRec
   for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) {
     const FieldDecl *FD = *it;
 
+    // Ignore zero-sized fields.
+    if (FD->isZeroSize(getContext()))
+      continue;
+
     // For non-bit-fields, just check that the LLVM struct offset matches the
     // AST offset.
     if (!FD->isBitField()) {
@@ -810,10 +824,6 @@ CGRecordLayout *CodeGenTypes::ComputeRec
     if (!FD->getDeclName())
       continue;
 
-    // Don't inspect zero-length bitfields.
-    if (FD->isZeroLengthBitField(getContext()))
-      continue;
-
     const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD);
     llvm::Type *ElementTy = ST->getTypeAtIndex(RL->getLLVMFieldNo(FD));
 

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu Jun 20 13:44:45 2019
@@ -2322,14 +2322,7 @@ public:
   }
 
   /// Determine whether a field initialization may overlap some other object.
-  AggValueSlot::Overlap_t overlapForFieldInit(const FieldDecl *FD) {
-    // FIXME: These cases can result in overlap as a result of P0840R0's
-    // [[no_unique_address]] attribute. We can still infer NoOverlap in the
-    // presence of that attribute if the field is within the nvsize of its
-    // containing class, because non-virtual subobjects are initialized in
-    // address order.
-    return AggValueSlot::DoesNotOverlap;
-  }
+  AggValueSlot::Overlap_t overlapForFieldInit(const FieldDecl *FD);
 
   /// Determine whether a base class initialization may overlap some other
   /// object.

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Thu Jun 20 13:44:45 2019
@@ -3912,6 +3912,7 @@ static bool IsBuiltInOrStandardCXX11Attr
   case ParsedAttr::AT_Deprecated:
   case ParsedAttr::AT_FallThrough:
   case ParsedAttr::AT_CXX11NoReturn:
+  case ParsedAttr::AT_NoUniqueAddress:
     return true;
   case ParsedAttr::AT_WarnUnusedResult:
     return !ScopeName && AttrName->getName().equals("nodiscard");

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Jun 20 13:44:45 2019
@@ -6813,6 +6813,9 @@ static void ProcessDeclAttribute(Sema &S
   case ParsedAttr::AT_NoSplitStack:
     handleSimpleAttribute<NoSplitStackAttr>(S, D, AL);
     break;
+  case ParsedAttr::AT_NoUniqueAddress:
+    handleSimpleAttribute<NoUniqueAddressAttr>(S, D, AL);
+    break;
   case ParsedAttr::AT_NonNull:
     if (auto *PVD = dyn_cast<ParmVarDecl>(D))
       handleNonNullAttrParameter(S, PVD, AL);

Added: cfe/trunk/test/CodeGenCXX/no-unique-address.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/no-unique-address.cpp?rev=363976&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/no-unique-address.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/no-unique-address.cpp Thu Jun 20 13:44:45 2019
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -std=c++2a %s -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s
+
+struct A { ~A(); int n; char c[3]; };
+struct B { [[no_unique_address]] A a; char k; };
+// CHECK-DAG: @b = global { i32, [3 x i8], i8 } { i32 1, [3 x i8] c"\02\03\04", i8 5 }
+B b = {1, 2, 3, 4, 5};
+
+struct C : A {};
+struct D : C {};
+struct E { int e; [[no_unique_address]] D d; char k; };
+// CHECK-DAG: @e = global { i32, i32, [3 x i8], i8 } { i32 1, i32 2, [3 x i8] c"\03\04\05", i8 6 }
+E e = {1, 2, 3, 4, 5, 6};
+
+struct Empty1 {};
+struct Empty2 {};
+struct Empty3 {};
+struct HasEmpty {
+  [[no_unique_address]] Empty1 e1;
+  int a;
+  [[no_unique_address]] Empty2 e2;
+  int b;
+  [[no_unique_address]] Empty3 e3;
+};
+// CHECK-DAG: @he = global %{{[^ ]*}} { i32 1, i32 2 }
+HasEmpty he = {{}, 1, {}, 2, {}};
+
+struct HasEmptyDuplicates {
+  [[no_unique_address]] Empty1 e1; // +0
+  int a;
+  [[no_unique_address]] Empty1 e2; // +4
+  int b;
+  [[no_unique_address]] Empty1 e3; // +8
+};
+// CHECK-DAG: @off1 = global i64 0
+Empty1 HasEmptyDuplicates::*off1 = &HasEmptyDuplicates::e1;
+// CHECK-DAG: @off2 = global i64 4
+Empty1 HasEmptyDuplicates::*off2 = &HasEmptyDuplicates::e2;
+// CHECK-DAG: @off3 = global i64 8
+Empty1 HasEmptyDuplicates::*off3 = &HasEmptyDuplicates::e3;
+
+// CHECK-DAG: @hed = global %{{[^ ]*}} { i32 1, i32 2, [4 x i8] undef }
+HasEmptyDuplicates hed = {{}, 1, {}, 2, {}};
+
+struct __attribute__((packed, aligned(2))) PackedAndPadded {
+  ~PackedAndPadded();
+  char c;
+  int n;
+};
+struct WithPackedAndPadded {
+  [[no_unique_address]] PackedAndPadded pap;
+  char d;
+};
+// CHECK-DAG: @wpap = global <{ i8, i32, i8 }> <{ i8 1, i32 2, i8 3 }>
+WithPackedAndPadded wpap = {1, 2, 3};
+
+struct FieldOverlap {
+  [[no_unique_address]] Empty1 e1, e2, e3, e4;
+  int n;
+};
+static_assert(sizeof(FieldOverlap) == 4);
+// CHECK-DAG: @fo = global %{{[^ ]*}} { i32 1234 }
+FieldOverlap fo = {{}, {}, {}, {}, 1234};
+
+// CHECK-DAG: @e1 = constant %[[E1:[^ ]*]]* bitcast (%[[FO:[^ ]*]]* @fo to %[[E1]]*)
+Empty1 &e1 = fo.e1;
+// CHECK-DAG: @e2 = constant %[[E1]]* bitcast (i8* getelementptr (i8, i8* bitcast (%[[FO]]* @fo to i8*), i64 1) to %[[E1]]*)
+Empty1 &e2 = fo.e2;
+
+// CHECK-LABEL: accessE1
+// CHECK: %[[RET:.*]] = bitcast %[[FO]]* %{{.*}} to %[[E1]]*
+// CHECK: ret %[[E1]]* %[[RET]]
+Empty1 &accessE1(FieldOverlap &fo) { return fo.e1; }
+
+// CHECK-LABEL: accessE2
+// CHECK: %[[AS_I8:.*]] = bitcast %[[FO]]* %{{.*}} to i8*
+// CHECK: %[[ADJUSTED:.*]] = getelementptr inbounds i8, i8* %[[AS_I8]], i64 1
+// CHECK: %[[RET:.*]] = bitcast i8* %[[ADJUSTED]] to %[[E1]]*
+// CHECK: ret %[[E1]]* %[[RET]]
+Empty1 &accessE2(FieldOverlap &fo) { return fo.e2; }

Modified: cfe/trunk/test/CodeGenCXX/tail-padding.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/tail-padding.cpp?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/tail-padding.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/tail-padding.cpp Thu Jun 20 13:44:45 2019
@@ -32,3 +32,47 @@ namespace InitWithinNVSize {
   // CHECK: store i32 {{.*}} @_ZTVN16InitWithinNVSize1CE
   // CHECK: store i8
 }
+
+namespace NoUniqueAddr {
+  struct A { char c; A(const A&); };
+  struct B { int n; char c[3]; ~B(); };
+  struct C : virtual A { B b; };
+  struct D : virtual A { [[no_unique_address]] B b; };
+  struct E : virtual A { [[no_unique_address]] B b; char x; };
+  static_assert(sizeof(C) == sizeof(void*) + 8 + alignof(void*));
+  static_assert(sizeof(D) == sizeof(void*) + 8);
+  static_assert(sizeof(E) == sizeof(void*) + 8 + alignof(void*));
+
+  // CHECK: define {{.*}} @_ZN12NoUniqueAddr1CC1EOS0_
+  // CHECK: call void @_ZN12NoUniqueAddr1AC2ERKS0_(
+  // CHECK: store i32 {{.*}} @_ZTVN12NoUniqueAddr1CE
+  // Copy the full size of B.
+  // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 8, i1 false)
+  C f(C c) { return c; }
+
+  // CHECK: define {{.*}} @_ZN12NoUniqueAddr1DC1EOS0_
+  // CHECK: call void @_ZN12NoUniqueAddr1AC2ERKS0_(
+  // CHECK: store i32 {{.*}} @_ZTVN12NoUniqueAddr1DE
+  // Copy just the data size of B, to avoid overwriting the A base class.
+  // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 7, i1 false)
+  D f(D d) { return d; }
+
+  // CHECK: define {{.*}} @_ZN12NoUniqueAddr1EC1EOS0_
+  // CHECK: call void @_ZN12NoUniqueAddr1AC2ERKS0_(
+  // CHECK: store i32 {{.*}} @_ZTVN12NoUniqueAddr1EE
+  // We can copy the full size of B here. (As it happens, we fold the copy of 'x' into
+  // this memcpy, so we're copying 8 bytes either way.)
+  // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 8, i1 false)
+  E f(E e) { return e; }
+
+  struct F : virtual A {
+    F(const F &o) : A(o), b(o.b) {}
+    [[no_unique_address]] B b;
+  };
+
+  // CHECK: define {{.*}} @_ZN12NoUniqueAddr1FC1ERKS0_
+  // CHECK: call void @_ZN12NoUniqueAddr1AC2ERKS0_(
+  // CHECK: store i32 {{.*}} @_ZTVN12NoUniqueAddr1FE
+  // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 7, i1 false)
+  F f(F x) { return x; }
+}

Added: cfe/trunk/test/Layout/no-unique-address.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Layout/no-unique-address.cpp?rev=363976&view=auto
==============================================================================
--- cfe/trunk/test/Layout/no-unique-address.cpp (added)
+++ cfe/trunk/test/Layout/no-unique-address.cpp Thu Jun 20 13:44:45 2019
@@ -0,0 +1,265 @@
+// RUN: %clang_cc1 -std=c++2a -fsyntax-only -triple x86_64-linux-gnu -fdump-record-layouts %s | FileCheck %s
+
+namespace Empty {
+  struct A {};
+  struct B { [[no_unique_address]] A a; char b; };
+  static_assert(sizeof(B) == 1);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct Empty::B
+  // CHECK-NEXT:     0 |   struct Empty::A a (empty)
+  // CHECK-NEXT:     0 |   char b
+  // CHECK-NEXT:       | [sizeof=1, dsize=1, align=1,
+  // CHECK-NEXT:       |  nvsize=1, nvalign=1]
+
+  struct C {};
+  struct D {
+    [[no_unique_address]] A a;
+    [[no_unique_address]] C c;
+    char d;
+  };
+  static_assert(sizeof(D) == 1);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct Empty::D
+  // CHECK-NEXT:     0 |   struct Empty::A a (empty)
+  // CHECK-NEXT:     0 |   struct Empty::C c (empty)
+  // CHECK-NEXT:     0 |   char d
+  // CHECK-NEXT:       | [sizeof=1, dsize=1, align=1,
+  // CHECK-NEXT:       |  nvsize=1, nvalign=1]
+
+  struct E {
+    [[no_unique_address]] A a1;
+    [[no_unique_address]] A a2;
+    char e;
+  };
+  static_assert(sizeof(E) == 2);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct Empty::E
+  // CHECK-NEXT:     0 |   struct Empty::A a1 (empty)
+  // CHECK-NEXT:     1 |   struct Empty::A a2 (empty)
+  // CHECK-NEXT:     0 |   char e
+  // CHECK-NEXT:       | [sizeof=2, dsize=2, align=1,
+  // CHECK-NEXT:       |  nvsize=2, nvalign=1]
+
+  struct F {
+    ~F();
+    [[no_unique_address]] A a1;
+    [[no_unique_address]] A a2;
+    char f;
+  };
+  static_assert(sizeof(F) == 2);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct Empty::F
+  // CHECK-NEXT:     0 |   struct Empty::A a1 (empty)
+  // CHECK-NEXT:     1 |   struct Empty::A a2 (empty)
+  // CHECK-NEXT:     0 |   char f
+  // CHECK-NEXT:       | [sizeof=2, dsize=1, align=1,
+  // CHECK-NEXT:       |  nvsize=2, nvalign=1]
+
+  struct G { [[no_unique_address]] A a; ~G(); };
+  static_assert(sizeof(G) == 1);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct Empty::G
+  // CHECK-NEXT:     0 |   struct Empty::A a (empty)
+  // CHECK-NEXT:       | [sizeof=1, dsize=0, align=1,
+  // CHECK-NEXT:       |  nvsize=1, nvalign=1]
+
+  struct H { [[no_unique_address]] A a, b; ~H(); };
+  static_assert(sizeof(H) == 2);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct Empty::H
+  // CHECK-NEXT:     0 |   struct Empty::A a (empty)
+  // CHECK-NEXT:     1 |   struct Empty::A b (empty)
+  // CHECK-NEXT:       | [sizeof=2, dsize=0, align=1,
+  // CHECK-NEXT:       |  nvsize=2, nvalign=1]
+
+  struct OversizedEmpty : A {
+    ~OversizedEmpty();
+    [[no_unique_address]] A a;
+  };
+  static_assert(sizeof(OversizedEmpty) == 2);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct Empty::OversizedEmpty
+  // CHECK-NEXT:     0 |   struct Empty::A (base) (empty)
+  // CHECK-NEXT:     1 |   struct Empty::A a (empty)
+  // CHECK-NEXT:       | [sizeof=2, dsize=0, align=1,
+  // CHECK-NEXT:       |  nvsize=2, nvalign=1]
+
+  struct HasOversizedEmpty {
+    [[no_unique_address]] OversizedEmpty m;
+  };
+  static_assert(sizeof(HasOversizedEmpty) == 2);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct Empty::HasOversizedEmpty
+  // CHECK-NEXT:     0 |   struct Empty::OversizedEmpty m (empty)
+  // CHECK-NEXT:     0 |     struct Empty::A (base) (empty)
+  // CHECK-NEXT:     1 |     struct Empty::A a (empty)
+  // CHECK-NEXT:       | [sizeof=2, dsize=0, align=1,
+  // CHECK-NEXT:       |  nvsize=2, nvalign=1]
+
+  struct EmptyWithNonzeroDSize {
+    [[no_unique_address]] A a;
+    int x;
+    [[no_unique_address]] A b;
+    int y;
+    [[no_unique_address]] A c;
+  };
+  static_assert(sizeof(EmptyWithNonzeroDSize) == 12);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct Empty::EmptyWithNonzeroDSize
+  // CHECK-NEXT:     0 |   struct Empty::A a (empty)
+  // CHECK-NEXT:     0 |   int x
+  // CHECK-NEXT:     4 |   struct Empty::A b (empty)
+  // CHECK-NEXT:     4 |   int y
+  // CHECK-NEXT:     8 |   struct Empty::A c (empty)
+  // CHECK-NEXT:       | [sizeof=12, dsize=12, align=4,
+  // CHECK-NEXT:       |  nvsize=12, nvalign=4]
+
+  struct EmptyWithNonzeroDSizeNonPOD {
+    ~EmptyWithNonzeroDSizeNonPOD();
+    [[no_unique_address]] A a;
+    int x;
+    [[no_unique_address]] A b;
+    int y;
+    [[no_unique_address]] A c;
+  };
+  static_assert(sizeof(EmptyWithNonzeroDSizeNonPOD) == 12);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct Empty::EmptyWithNonzeroDSizeNonPOD
+  // CHECK-NEXT:     0 |   struct Empty::A a (empty)
+  // CHECK-NEXT:     0 |   int x
+  // CHECK-NEXT:     4 |   struct Empty::A b (empty)
+  // CHECK-NEXT:     4 |   int y
+  // CHECK-NEXT:     8 |   struct Empty::A c (empty)
+  // CHECK-NEXT:       | [sizeof=12, dsize=8, align=4,
+  // CHECK-NEXT:       |  nvsize=9, nvalign=4]
+}
+
+namespace POD {
+  // Cannot reuse tail padding of a PDO type.
+  struct A { int n; char c[3]; };
+  struct B { [[no_unique_address]] A a; char d; };
+  static_assert(sizeof(B) == 12);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct POD::B
+  // CHECK-NEXT:     0 |   struct POD::A a
+  // CHECK-NEXT:     0 |     int n
+  // CHECK-NEXT:     4 |     char [3] c
+  // CHECK-NEXT:     8 |   char d
+  // CHECK-NEXT:       | [sizeof=12, dsize=12, align=4,
+  // CHECK-NEXT:       |  nvsize=12, nvalign=4]
+}
+
+namespace NonPOD {
+  struct A { int n; char c[3]; ~A(); };
+  struct B { [[no_unique_address]] A a; char d; };
+  static_assert(sizeof(B) == 8);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct NonPOD::B
+  // CHECK-NEXT:     0 |   struct NonPOD::A a
+  // CHECK-NEXT:     0 |     int n
+  // CHECK-NEXT:     4 |     char [3] c
+  // CHECK-NEXT:     7 |   char d
+  // CHECK-NEXT:       | [sizeof=8, dsize=8, align=4,
+  // CHECK-NEXT:       |  nvsize=8, nvalign=4]
+}
+
+namespace NVSizeGreaterThanDSize {
+  // The nvsize of an object includes the complete size of its empty subobjects
+  // (although it's unclear why). Ensure this corner case is handled properly.
+  struct alignas(8) A { ~A(); }; // dsize 0, nvsize 0, size 8
+  struct B : A { char c; }; // dsize 1, nvsize 8, size 8
+  static_assert(sizeof(B) == 8);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct NVSizeGreaterThanDSize::B
+  // CHECK-NEXT:     0 |   struct NVSizeGreaterThanDSize::A (base) (empty)
+  // CHECK-NEXT:     0 |   char c
+  // CHECK-NEXT:       | [sizeof=8, dsize=1, align=8,
+  // CHECK-NEXT:       |  nvsize=8, nvalign=8]
+
+  struct V { int n; };
+
+  // V is at offset 16, not offset 12, because B's tail padding is strangely not
+  // usable for virtual bases.
+  struct C : B, virtual V {};
+  static_assert(sizeof(C) == 24);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct NVSizeGreaterThanDSize::C
+  // CHECK-NEXT:     0 |   (C vtable pointer)
+  // CHECK-NEXT:     8 |   struct NVSizeGreaterThanDSize::B (base)
+  // CHECK-NEXT:     8 |     struct NVSizeGreaterThanDSize::A (base) (empty)
+  // CHECK-NEXT:     8 |     char c
+  // CHECK-NEXT:    16 |   struct NVSizeGreaterThanDSize::V (virtual base)
+  // CHECK-NEXT:    16 |     int n
+  // CHECK-NEXT:       | [sizeof=24, dsize=20, align=8,
+  // CHECK-NEXT:       |  nvsize=16, nvalign=8]
+
+  struct D : virtual V {
+    [[no_unique_address]] B b;
+  };
+  static_assert(sizeof(D) == 24);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct NVSizeGreaterThanDSize::D
+  // CHECK-NEXT:     0 |   (D vtable pointer)
+  // CHECK-NEXT:     8 |   struct NVSizeGreaterThanDSize::B b
+  // CHECK-NEXT:     8 |     struct NVSizeGreaterThanDSize::A (base) (empty)
+  // CHECK-NEXT:     8 |     char c
+  // CHECK-NEXT:    16 |   struct NVSizeGreaterThanDSize::V (virtual base)
+  // CHECK-NEXT:    16 |     int n
+  // CHECK-NEXT:       | [sizeof=24, dsize=20, align=8,
+  // CHECK-NEXT:       |  nvsize=16, nvalign=8]
+
+  struct X : virtual A { [[no_unique_address]] A a; };
+  struct E : virtual A {
+    [[no_unique_address]] A a;
+    // Here, we arrange for X to hang over the end of the nvsize of E. This
+    // should force the A vbase to be laid out at offset 24, not 16.
+    [[no_unique_address]] X x;
+  };
+  static_assert(sizeof(E) == 32);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct NVSizeGreaterThanDSize::E
+  // CHECK-NEXT:     0 |   (E vtable pointer)
+  // CHECK-NEXT:     0 |   struct NVSizeGreaterThanDSize::A a (empty)
+  // CHECK-NEXT:     8 |   struct NVSizeGreaterThanDSize::X x
+  // CHECK-NEXT:     8 |     (X vtable pointer)
+  // CHECK-NEXT:     8 |     struct NVSizeGreaterThanDSize::A a (empty)
+  // CHECK-NEXT:    16 |     struct NVSizeGreaterThanDSize::A (virtual base) (empty)
+  // CHECK-NEXT:    24 |   struct NVSizeGreaterThanDSize::A (virtual base) (empty)
+  // CHECK-NEXT:       | [sizeof=32, dsize=16, align=8,
+  // CHECK-NEXT:       |  nvsize=16, nvalign=8]
+}
+
+namespace RepeatedVBase {
+  struct alignas(16) A { ~A(); };
+  struct B : A {};
+  struct X : virtual A, virtual B {};
+  struct Y { [[no_unique_address]] X x; char c; };
+  static_assert(sizeof(Y) == 32);
+
+  // CHECK:*** Dumping AST Record Layout
+  // CHECK:          0 | struct RepeatedVBase::Y
+  // CHECK-NEXT:     0 |   struct RepeatedVBase::X x
+  // CHECK-NEXT:     0 |     (X vtable pointer)
+  // CHECK-NEXT:     0 |     struct RepeatedVBase::A (virtual base) (empty)
+  // CHECK-NEXT:    16 |     struct RepeatedVBase::B (virtual base) (empty)
+  // CHECK-NEXT:    16 |       struct RepeatedVBase::A (base) (empty)
+  // CHECK-NEXT:     8 |     char c
+  // CHECK-NEXT:       | [sizeof=32, dsize=9, align=16,
+  // CHECK-NEXT:       |  nvsize=9, nvalign=16]
+}

Added: cfe/trunk/test/SemaCXX/cxx2a-no-unique-address.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx2a-no-unique-address.cpp?rev=363976&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx2a-no-unique-address.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx2a-no-unique-address.cpp Thu Jun 20 13:44:45 2019
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++2a %s -verify -triple x86_64-linux-gnu
+// RUN: %clang_cc1 -std=c++2a %s -verify=unsupported -triple x86_64-windows
+
+[[no_unique_address]] int a; // expected-error {{only applies to non-bit-field non-static data members}} unsupported-warning {{unknown}}
+[[no_unique_address]] void f(); // expected-error {{only applies to non-bit-field non-static data members}} unsupported-warning {{unknown}}
+struct [[no_unique_address]] S { // expected-error {{only applies to non-bit-field non-static data members}} unsupported-warning {{unknown}}
+  [[no_unique_address]] int a; // unsupported-warning {{unknown}}
+  [[no_unique_address]] void f(); // expected-error {{only applies to non-bit-field non-static data members}} unsupported-warning {{unknown}}
+  [[no_unique_address]] static int sa;// expected-error {{only applies to non-bit-field non-static data members}} unsupported-warning {{unknown}}
+  [[no_unique_address]] static void sf(); // expected-error {{only applies to non-bit-field non-static data members}} unsupported-warning {{unknown}}
+  [[no_unique_address]] int b : 3; // expected-error {{only applies to non-bit-field non-static data members}} unsupported-warning {{unknown}}
+
+  [[no_unique_address, no_unique_address]] int duplicated; // expected-error {{cannot appear multiple times}}
+  // unsupported-error at -1 {{cannot appear multiple times}} unsupported-warning at -1 2{{unknown}}
+  [[no_unique_address]] [[no_unique_address]] int duplicated2; // unsupported-warning 2{{unknown}}
+  [[no_unique_address()]] int arglist; // expected-error {{cannot have an argument list}} unsupported-warning {{unknown}}
+
+  int [[no_unique_address]] c; // expected-error {{cannot be applied to types}} unsupported-error {{cannot be applied to types}}
+};

Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Thu Jun 20 13:44:45 2019
@@ -2810,7 +2810,7 @@ void EmitClangAttrPCHWrite(RecordKeeper
 
 // Helper function for GenerateTargetSpecificAttrChecks that alters the 'Test'
 // parameter with only a single check type, if applicable.
-static void GenerateTargetSpecificAttrCheck(const Record *R, std::string &Test,
+static bool GenerateTargetSpecificAttrCheck(const Record *R, std::string &Test,
                                             std::string *FnName,
                                             StringRef ListName,
                                             StringRef CheckAgainst,
@@ -2830,7 +2830,9 @@ static void GenerateTargetSpecificAttrCh
         *FnName += Part;
     }
     Test += ")";
+    return true;
   }
+  return false;
 }
 
 // Generate a conditional expression to check if the current target satisfies
@@ -2838,10 +2840,12 @@ static void GenerateTargetSpecificAttrCh
 // those checks to the Test string. If the FnName string pointer is non-null,
 // append a unique suffix to distinguish this set of target checks from other
 // TargetSpecificAttr records.
-static void GenerateTargetSpecificAttrChecks(const Record *R,
+static bool GenerateTargetSpecificAttrChecks(const Record *R,
                                              std::vector<StringRef> &Arches,
                                              std::string &Test,
                                              std::string *FnName) {
+  bool AnyTargetChecks = false;
+
   // It is assumed that there will be an llvm::Triple object
   // named "T" and a TargetInfo object named "Target" within
   // scope that can be used to determine whether the attribute exists in
@@ -2851,6 +2855,7 @@ static void GenerateTargetSpecificAttrCh
   // differently because GenerateTargetRequirements needs to combine the list
   // with ParseKind.
   if (!Arches.empty()) {
+    AnyTargetChecks = true;
     Test += " && (";
     for (auto I = Arches.begin(), E = Arches.end(); I != E; ++I) {
       StringRef Part = *I;
@@ -2865,16 +2870,24 @@ static void GenerateTargetSpecificAttrCh
   }
 
   // If the attribute is specific to particular OSes, check those.
-  GenerateTargetSpecificAttrCheck(R, Test, FnName, "OSes", "T.getOS()",
-                                  "llvm::Triple::");
+  AnyTargetChecks |= GenerateTargetSpecificAttrCheck(
+      R, Test, FnName, "OSes", "T.getOS()", "llvm::Triple::");
 
-  // If one or more CXX ABIs are specified, check those as well.
-  GenerateTargetSpecificAttrCheck(R, Test, FnName, "CXXABIs",
-                                  "Target.getCXXABI().getKind()",
-                                  "TargetCXXABI::");
   // If one or more object formats is specified, check those.
-  GenerateTargetSpecificAttrCheck(R, Test, FnName, "ObjectFormats",
-                                  "T.getObjectFormat()", "llvm::Triple::");
+  AnyTargetChecks |=
+      GenerateTargetSpecificAttrCheck(R, Test, FnName, "ObjectFormats",
+                                      "T.getObjectFormat()", "llvm::Triple::");
+
+  // If custom code is specified, emit it.
+  StringRef Code = R->getValueAsString("CustomCode");
+  if (!Code.empty()) {
+    AnyTargetChecks = true;
+    Test += " && (";
+    Test += Code;
+    Test += ")";
+  }
+
+  return AnyTargetChecks;
 }
 
 static void GenerateHasAttrSpellingStringSwitch(
@@ -3510,7 +3523,7 @@ static std::string GenerateTargetRequire
 
   std::string FnName = "isTarget";
   std::string Test;
-  GenerateTargetSpecificAttrChecks(R, Arches, Test, &FnName);
+  bool UsesT = GenerateTargetSpecificAttrChecks(R, Arches, Test, &FnName);
 
   // If this code has already been generated, simply return the previous
   // instance of it.
@@ -3520,7 +3533,8 @@ static std::string GenerateTargetRequire
     return *I;
 
   OS << "static bool " << FnName << "(const TargetInfo &Target) {\n";
-  OS << "  const llvm::Triple &T = Target.getTriple();\n";
+  if (UsesT)
+    OS << "  const llvm::Triple &T = Target.getTriple(); (void)T;\n";
   OS << "  return " << Test << ";\n";
   OS << "}\n\n";
 

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=363976&r1=363975&r2=363976&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Thu Jun 20 13:44:45 2019
@@ -934,7 +934,7 @@ as the draft C++2a standard evolves.
     <tr>
       <td><tt>[[no_unique_address]]</tt> attribute</td>
       <td><a href="http://wg21.link/p0840r2">P0840R2</a></td>
-      <td class="none" align="center">No</td>
+      <td class="svn" align="center">SVN</td>
     </tr>
     <tr>
       <td><tt>[[likely]]</tt> and <tt>[[unlikely]]</tt> attributes</td>




More information about the cfe-commits mailing list