dzhidzhoev created this revision.
dzhidzhoev added reviewers: kjdyck, rjmccall, efriedma, majnemer, 
aaron.ballman, rsmith.
Herald added a project: All.
dzhidzhoev requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

RecordLayoutBuilder assumes the size of a potentially-overlapping field
with non-zero size as the size of the base subobject type corresponding
to the field type.
Make RecordLayoutBuilder to acknowledge that in order to avoid incorrect
padding insertion.

Without this patch, test fails on assertion

  Assertion failed: (Offset >= Size), function insertPadding, file 
CGRecordLayoutBuilder.cpp, line 802.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D139741

Files:
  clang/include/clang/AST/Decl.h
  clang/lib/AST/Decl.cpp
  clang/lib/AST/RecordLayoutBuilder.cpp
  clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
  clang/test/CodeGenCXX/no-unique-address-3.cpp

Index: clang/test/CodeGenCXX/no-unique-address-3.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/no-unique-address-3.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -emit-obj -fdump-record-layouts -std=c++17 %s -o %t | FileCheck %s
+
+// CHECK:       *** Dumping AST Record Layout
+// CHECK-NEXT:           0 | class Empty (empty)
+// CHECK-NEXT:             | [sizeof=1, dsize=1, align=1,
+// CHECK-NEXT:             |  nvsize=1, nvalign=1]
+
+// CHECK:       *** Dumping AST Record Layout
+// CHECK-NEXT:           0 | class Second
+// CHECK-NEXT:           0 |   class Empty (base) (empty)
+// CHECK-NEXT:       0:0-0 |   short A
+// CHECK-NEXT:             | [sizeof=2, dsize=1, align=2,
+// CHECK-NEXT:             |  nvsize=1, nvalign=2]
+
+// CHECK:       *** Dumping AST Record Layout
+// CHECK-NEXT:           0 | class Foo
+// CHECK-NEXT:           0 |   class Empty (base) (empty)
+// CHECK-NEXT:           2 |   class Second NZNoUnique
+// CHECK-NEXT:           2 |     class Empty (base) (empty)
+// CHECK-NEXT:       2:0-0 |     short A
+// CHECK-NEXT:           3 |   char B
+// CHECK-NEXT:             | [sizeof=4, dsize=4, align=2,
+// CHECK-NEXT:             |  nvsize=4, nvalign=2]
+
+// CHECK:       *** Dumping AST Record Layout
+// CHECK-NEXT:           0 | class SecondEmpty (empty)
+// CHECK-NEXT:           0 |   class Empty (base) (empty)
+// CHECK-NEXT:             | [sizeof=1, dsize=0, align=1,
+// CHECK-NEXT:             |  nvsize=1, nvalign=1]
+
+// CHECK:       *** Dumping AST Record Layout
+// CHECK-NEXT:           0 | class Bar
+// CHECK-NEXT:           0 |   class Empty (base) (empty)
+// CHECK-NEXT:           1 |   class SecondEmpty ZNoUnique (empty)
+// CHECK-NEXT:           1 |     class Empty (base) (empty)
+// CHECK-NEXT:           0 |   char C
+// CHECK-NEXT:             | [sizeof=2, dsize=1, align=1,
+// CHECK-NEXT:             |  nvsize=2, nvalign=1]
+
+// CHECK:       *** Dumping AST Record Layout
+// CHECK-NEXT:           0 | class IntFieldClass
+// CHECK-NEXT:           0 |   class Empty (base) (empty)
+// CHECK-NEXT:           2 |   class Second Field
+// CHECK-NEXT:           2 |     class Empty (base) (empty)
+// CHECK-NEXT:       2:0-0 |     short A
+// CHECK-NEXT:           4 |   int C
+// CHECK-NEXT:             | [sizeof=8, dsize=8, align=4,
+// CHECK-NEXT:             |  nvsize=8, nvalign=4]
+
+class Empty {};
+
+class Second : Empty {
+  short A : 1;
+};
+
+class Foo : Empty {
+  [[no_unique_address]] Second NZNoUnique;
+  char B;
+};
+Foo I;
+
+class SecondEmpty: Empty {
+};
+class Bar : Empty {
+  [[no_unique_address]] SecondEmpty ZNoUnique;
+  char C;
+};
+Bar J;
+
+class IntFieldClass : Empty {
+  [[no_unique_address]] Second Field;
+  int C;
+};
+IntFieldClass K;
Index: clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
===================================================================
--- clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -379,9 +379,14 @@
       for (++Field; Field != FieldEnd && Field->isBitField(); ++Field);
       accumulateBitFields(Start, Field);
     } else if (!Field->isZeroSize(Context)) {
+      // Use base subobject layout for the potentially-overlapping field,
+      // as it is done in RecordLayoutBuilder
       Members.push_back(MemberInfo(
           bitsToCharUnits(getFieldBitOffset(*Field)), MemberInfo::Field,
-          getStorageType(*Field), *Field));
+          (Field->isPotentiallyOverlapping()
+               ? getStorageType(Field->getType()->getAsCXXRecordDecl())
+               : getStorageType(*Field)),
+          *Field));
       ++Field;
     } else {
       ++Field;
Index: clang/lib/AST/RecordLayoutBuilder.cpp
===================================================================
--- clang/lib/AST/RecordLayoutBuilder.cpp
+++ clang/lib/AST/RecordLayoutBuilder.cpp
@@ -1853,9 +1853,8 @@
 void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
                                              bool InsertExtraPadding) {
   auto *FieldClass = D->getType()->getAsCXXRecordDecl();
-  bool PotentiallyOverlapping = D->hasAttr<NoUniqueAddressAttr>() && FieldClass;
   bool IsOverlappingEmptyField =
-      PotentiallyOverlapping && FieldClass->isEmpty();
+      D->isPotentiallyOverlapping() && FieldClass->isEmpty();
 
   CharUnits FieldOffset =
       (IsUnion || IsOverlappingEmptyField) ? CharUnits::Zero() : getDataSize();
@@ -1916,7 +1915,7 @@
 
     // A potentially-overlapping field occupies its dsize or nvsize, whichever
     // is larger.
-    if (PotentiallyOverlapping) {
+    if (D->isPotentiallyOverlapping()) {
       const ASTRecordLayout &Layout = Context.getASTRecordLayout(FieldClass);
       EffectiveFieldSize =
           std::max(Layout.getNonVirtualSize(), Layout.getDataSize());
Index: clang/lib/AST/Decl.cpp
===================================================================
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -4339,6 +4339,10 @@
   return true;
 }
 
+bool FieldDecl::isPotentiallyOverlapping() const {
+  return hasAttr<NoUniqueAddressAttr>() && getType()->getAsCXXRecordDecl();
+}
+
 unsigned FieldDecl::getFieldIndex() const {
   const FieldDecl *Canonical = getCanonicalDecl();
   if (Canonical != this)
Index: clang/include/clang/AST/Decl.h
===================================================================
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -3059,6 +3059,10 @@
   /// [[no_unique_address]] attribute.
   bool isZeroSize(const ASTContext &Ctx) const;
 
+  /// Determine if this field is a potentially-overlapping, that is,
+  /// subobject with the [[no_unique_address]] attribute
+  bool isPotentiallyOverlapping() const;
+
   /// Get the kind of (C++11) default member initializer that this field has.
   InClassInitStyle getInClassInitStyle() const {
     InitStorageKind storageKind = InitStorage.getInt();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to