Skip to content

Commit a7c1744

Browse files
committed
[cxx-interop] Do not crash when emitting layout of std::string
If a `[[no_unique_address]]` field has zero size according to Clang, and field has a type that isn't representable in Swift, Swift would previously try to add an opaque field of size 1 for it. This is wrong and was causing crashes for `std::string` while emitting a padding field: ``` _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T1> _LIBCPP_CONCAT3(__padding1_, __LINE__, _); ``` rdar://151941799
1 parent 278248e commit a7c1744

File tree

3 files changed

+33
-5
lines changed

3 files changed

+33
-5
lines changed

lib/IRGen/GenStruct.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,12 +1461,12 @@ class ClangRecordLowering {
14611461
unsigned fieldOffset = layout.getFieldOffset(clangField->getFieldIndex());
14621462
assert(!clangField->isBitField());
14631463
Size offset( SubobjectAdjustment.getValue() + fieldOffset / 8);
1464-
std::optional<Size> dataSize;
1464+
std::optional<clang::CharUnits> dataSize;
14651465
if (clangField->hasAttr<clang::NoUniqueAddressAttr>()) {
14661466
if (const auto *rd = clangField->getType()->getAsRecordDecl()) {
14671467
// Clang can store the next field in the padding of this one.
14681468
const auto &fieldLayout = ClangContext.getASTRecordLayout(rd);
1469-
dataSize = Size(fieldLayout.getDataSize().getQuantity());
1469+
dataSize = fieldLayout.getDataSize();
14701470
}
14711471
}
14721472

@@ -1480,9 +1480,10 @@ class ClangRecordLowering {
14801480
}
14811481

14821482
// Otherwise, add it as an opaque blob.
1483-
auto fieldSize = isZeroSized ? clang::CharUnits::Zero() : ClangContext.getTypeSizeInChars(clangField->getType());
1484-
return addOpaqueField(offset,
1485-
dataSize.value_or(Size(fieldSize.getQuantity())));
1483+
auto fieldTypeSize = ClangContext.getTypeSizeInChars(clangField->getType());
1484+
auto fieldSize = isZeroSized ? clang::CharUnits::Zero()
1485+
: dataSize.value_or(fieldTypeSize);
1486+
return addOpaqueField(offset, Size(fieldSize.getQuantity()));
14861487
}
14871488

14881489
/// Add opaque storage for bitfields spanning the given range of bits.

test/Interop/Cxx/class/Inputs/member-variables.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,21 @@ inline int takesZeroSizedInCpp(HasZeroSizedField x) {
8383
return x.a;
8484
}
8585

86+
/// Not imported into Swift.
87+
struct EmptyNotImported {
88+
char : 0;
89+
90+
EmptyNotImported() = default;
91+
EmptyNotImported(const EmptyNotImported &) = delete;
92+
EmptyNotImported(EmptyNotImported &&) = delete;
93+
};
94+
95+
struct LastFieldNoUniqueAddress {
96+
char c;
97+
[[no_unique_address]] EmptyNotImported p0;
98+
99+
LastFieldNoUniqueAddress(const LastFieldNoUniqueAddress &other) {}
100+
LastFieldNoUniqueAddress(LastFieldNoUniqueAddress &&other) {}
101+
};
102+
86103
#endif

test/Interop/Cxx/class/zero-sized-field.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,14 @@ FieldsTestSuite.test("Non-standard-layout field padding in templated class reuse
8383
expectEqual(s2.get_c(), 6)
8484
}
8585

86+
FieldsTestSuite.test("Last field is no unique address") {
87+
var s = LastFieldNoUniqueAddress()
88+
89+
s.c = 5
90+
expectEqual(s.c, 5)
91+
92+
s.c = 6
93+
expectEqual(s.c, 6)
94+
}
95+
8696
runAllTests()

0 commit comments

Comments
 (0)