diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index d9bf62c2bbb04..76e5007357e4d 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -1296,13 +1296,6 @@ ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { bool Allowed = EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset); (void)Allowed; assert(Allowed && "Base subobject externally placed at overlapping offset"); - - if (InferAlignment && Offset < getDataSize().alignTo(AlignTo)) { - // The externally-supplied base offset is before the base offset we - // computed. Assume that the structure is packed. - Alignment = CharUnits::One(); - InferAlignment = false; - } } if (!Base->Class->isEmpty()) { @@ -2255,9 +2248,27 @@ ItaniumRecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field, uint64_t ComputedOffset) { uint64_t ExternalFieldOffset = External.getExternalFieldOffset(Field); - if (InferAlignment && ExternalFieldOffset < ComputedOffset) { - // The externally-supplied field offset is before the field offset we - // computed. Assume that the structure is packed. + // DWARF doesn't tell us whether a structure was declared as packed. + // So we try to figure out if the supplied Field is at a packed offset + // (i.e., the externally-supplied offset is less than the layout builder + // expected). + // + // There are cases where fields are placed at overlapping offsets (e.g., + // as a result of [[no_unique_address]]). In those cases we don't want + // to incorrectly deduce that they are placed at packed offsets. Hence, + // ignore empty fields (which are the only fields that can overlap). + // + // FIXME: emit enough information in DWARF to get rid of InferAlignment. + // + CXXRecordDecl *CXX = nullptr; + if (auto *RT = dyn_cast(Field->getType())) + CXX = RT->getAsCXXRecordDecl(); + + const bool assume_packed = ExternalFieldOffset > 0 && + ExternalFieldOffset < ComputedOffset && + !(CXX && CXX->isEmpty()); + + if (InferAlignment && assume_packed) { Alignment = CharUnits::One(); PreferredAlignment = CharUnits::One(); InferAlignment = false; diff --git a/lldb/test/Shell/SymbolFile/DWARF/no_unique_address-packed-alignment.cpp b/lldb/test/Shell/SymbolFile/DWARF/no_unique_address-packed-alignment.cpp new file mode 100644 index 0000000000000..e47dab45ff7b7 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/no_unique_address-packed-alignment.cpp @@ -0,0 +1,23 @@ +// RUN: %clangxx_host -gdwarf -o %t %s +// RUN: %lldb %t \ +// RUN: -o "expr alignof(PackedNUA)" \ +// RUN: -o "expr sizeof(PackedNUA)" \ +// RUN: -o exit | FileCheck %s + +struct Empty {}; +struct __attribute((packed)) PackedNUA { + [[no_unique_address]] Empty a, b, c, d; + char x; + int y; +}; +static_assert(alignof(PackedNUA) == 1); +static_assert(sizeof(PackedNUA) == 5); + +PackedNUA packed; + +// CHECK: (lldb) expr alignof(PackedNUA) +// CHECK-NEXT: ${{.*}} = 1 +// CHECK: (lldb) expr sizeof(PackedNUA) +// CHECK-NEXT: ${{.*}} = 5 + +int main() { PackedNUA d; } diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/no_unique_address-alignment.cpp b/lldb/test/Shell/SymbolFile/DWARF/x86/no_unique_address-alignment.cpp index e198bf0cafeaa..cf499388c56d5 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/x86/no_unique_address-alignment.cpp +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/no_unique_address-alignment.cpp @@ -1,5 +1,3 @@ -// XFAIL: * - // RUN: %clang --target=x86_64-apple-macosx -c -gdwarf -o %t %s // RUN: %lldb %t \ // RUN: -o "expr alignof(OverlappingFields)" \ diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/no_unique_address-base-alignment.cpp b/lldb/test/Shell/SymbolFile/DWARF/x86/no_unique_address-base-alignment.cpp index c4bcfc473277f..2cf1eb30d7a26 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/x86/no_unique_address-base-alignment.cpp +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/no_unique_address-base-alignment.cpp @@ -1,5 +1,3 @@ -// XFAIL: * - // RUN: %clang --target=x86_64-apple-macosx -c -gdwarf -o %t %s // RUN: %lldb %t \ // RUN: -o "expr alignof(OverlappingDerived)" \