Skip to content

Commit 68d71ab

Browse files
committed
fixup! ignore empty fields instead of checking overlap
1 parent 38b7837 commit 68d71ab

File tree

2 files changed

+47
-13
lines changed

2 files changed

+47
-13
lines changed

clang/lib/AST/RecordLayoutBuilder.cpp

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -802,8 +802,7 @@ class ItaniumRecordLayoutBuilder {
802802
/// \param Field The field whose offset is being queried.
803803
/// \param ComputedOffset The offset that we've computed for this field.
804804
uint64_t updateExternalFieldOffset(const FieldDecl *Field,
805-
uint64_t ComputedOffset,
806-
uint64_t PreviousOffset);
805+
uint64_t ComputedOffset);
807806

808807
void CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset,
809808
uint64_t UnpackedOffset, unsigned UnpackedAlign,
@@ -1764,8 +1763,7 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
17641763
// If we're using external layout, give the external layout a chance
17651764
// to override this information.
17661765
if (UseExternalLayout)
1767-
FieldOffset = updateExternalFieldOffset(
1768-
D, FieldOffset, FieldOffsets.empty() ? 0 : FieldOffsets.back());
1766+
FieldOffset = updateExternalFieldOffset(D, FieldOffset);
17691767

17701768
// Okay, place the bitfield at the calculated offset.
17711769
FieldOffsets.push_back(FieldOffset);
@@ -2058,9 +2056,8 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
20582056
UnpackedFieldOffset = UnpackedFieldOffset.alignTo(UnpackedFieldAlign);
20592057

20602058
if (UseExternalLayout) {
2061-
FieldOffset = Context.toCharUnitsFromBits(updateExternalFieldOffset(
2062-
D, Context.toBits(FieldOffset),
2063-
FieldOffsets.empty() ? 0 : FieldOffsets.back()));
2059+
FieldOffset = Context.toCharUnitsFromBits(
2060+
updateExternalFieldOffset(D, Context.toBits(FieldOffset)));
20642061

20652062
if (!IsUnion && EmptySubobjects) {
20662063
// Record the fact that we're placing a field at this offset.
@@ -2246,16 +2243,30 @@ void ItaniumRecordLayoutBuilder::UpdateAlignment(
22462243
}
22472244
}
22482245

2249-
uint64_t ItaniumRecordLayoutBuilder::updateExternalFieldOffset(
2250-
const FieldDecl *Field, uint64_t ComputedOffset, uint64_t PreviousOffset) {
2246+
uint64_t
2247+
ItaniumRecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field,
2248+
uint64_t ComputedOffset) {
22512249
uint64_t ExternalFieldOffset = External.getExternalFieldOffset(Field);
22522250

2253-
// If the externally-supplied field offset is before the field offset we
2254-
// computed. Check against the previous field offset to make sure we don't
2255-
// misinterpret overlapping fields as packedness of the structure.
2251+
// DWARF doesn't tell us whether a structure was declared as packed.
2252+
// So we try to figure out if the supplied Field is at a packed offset
2253+
// (i.e., the externally-supplied offset is less than the layout builder
2254+
// expected).
2255+
//
2256+
// There are cases where fields are placed at overlapping offsets (e.g.,
2257+
// as a result of [[no_unique_address]]). In those cases we don't want
2258+
// to incorrectly deduce that they are placed at packed offsets. Hence,
2259+
// ignore empty fields (which are the only fields that can overlap).
2260+
//
2261+
// FIXME: emit enough information in DWARF to get rid of InferAlignment.
2262+
//
2263+
CXXRecordDecl *CXX = nullptr;
2264+
if (auto *RT = dyn_cast<RecordType>(Field->getType()))
2265+
CXX = RT->getAsCXXRecordDecl();
2266+
22562267
const bool assume_packed = ExternalFieldOffset > 0 &&
22572268
ExternalFieldOffset < ComputedOffset &&
2258-
ExternalFieldOffset > PreviousOffset;
2269+
!(CXX && CXX->isEmpty());
22592270

22602271
if (InferAlignment && assume_packed) {
22612272
Alignment = CharUnits::One();
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %clangxx_host -gdwarf -o %t %s
2+
// RUN: %lldb %t \
3+
// RUN: -o "expr alignof(PackedNUA)" \
4+
// RUN: -o "expr sizeof(PackedNUA)" \
5+
// RUN: -o exit | FileCheck %s
6+
7+
struct Empty {};
8+
struct __attribute((packed)) PackedNUA {
9+
[[no_unique_address]] Empty a,b,c,d;
10+
char x;
11+
int y;
12+
};
13+
static_assert(alignof(PackedNUA) == 1);
14+
static_assert(sizeof(PackedNUA) == 5);
15+
16+
PackedNUA packed;
17+
18+
// CHECK: (lldb) expr alignof(PackedNUA)
19+
// CHECK-NEXT: ${{.*}} = 1
20+
// CHECK: (lldb) expr sizeof(PackedNUA)
21+
// CHECK-NEXT: ${{.*}} = 5
22+
23+
int main() { PackedNUA d; }

0 commit comments

Comments
 (0)