@@ -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 ();
0 commit comments