Skip to content

Commit 40deafb

Browse files
authoredFeb 3, 2025
Merge pull request swiftlang#79076 from swiftlang/gaborh/zero-sized-field-import
[cxx-interop] Do not codegen zero-sized fields
2 parents d2d5ad6 + 998591e commit 40deafb

File tree

3 files changed

+67
-13
lines changed

3 files changed

+67
-13
lines changed
 

‎lib/IRGen/GenStruct.cpp

+18-13
Original file line numberDiff line numberDiff line change
@@ -1451,6 +1451,7 @@ class ClangRecordLowering {
14511451
/// Place the next struct field at its appropriate offset.
14521452
void addStructField(const clang::FieldDecl *clangField,
14531453
VarDecl *swiftField, const clang::ASTRecordLayout &layout) {
1454+
bool isZeroSized = clangField->isZeroSize(ClangContext);
14541455
unsigned fieldOffset = layout.getFieldOffset(clangField->getFieldIndex());
14551456
assert(!clangField->isBitField());
14561457
Size offset( SubobjectAdjustment.getValue() + fieldOffset / 8);
@@ -1460,12 +1461,12 @@ class ClangRecordLowering {
14601461
auto &fieldTI = cast<FixedTypeInfo>(IGM.getTypeInfo(
14611462
SwiftType.getFieldType(swiftField, IGM.getSILModule(),
14621463
IGM.getMaximalTypeExpansionContext())));
1463-
addField(swiftField, offset, fieldTI);
1464+
addField(swiftField, offset, fieldTI, isZeroSized);
14641465
return;
14651466
}
14661467

14671468
// Otherwise, add it as an opaque blob.
1468-
auto fieldSize = ClangContext.getTypeSizeInChars(clangField->getType());
1469+
auto fieldSize = isZeroSized ? clang::CharUnits::Zero() : ClangContext.getTypeSizeInChars(clangField->getType());
14691470
return addOpaqueField(offset, Size(fieldSize.getQuantity()));
14701471
}
14711472

@@ -1491,23 +1492,23 @@ class ClangRecordLowering {
14911492
if (fieldSize.isZero()) return;
14921493

14931494
auto &opaqueTI = IGM.getOpaqueStorageTypeInfo(fieldSize, Alignment(1));
1494-
addField(nullptr, offset, opaqueTI);
1495+
addField(nullptr, offset, opaqueTI, false);
14951496
}
14961497

14971498
/// Add storage for an (optional) Swift field at the given offset.
14981499
void addField(VarDecl *swiftField, Size offset,
1499-
const FixedTypeInfo &fieldType) {
1500-
assert(offset >= NextOffset && "adding fields out of order");
1500+
const FixedTypeInfo &fieldType, bool isZeroSized) {
1501+
assert(isZeroSized || offset >= NextOffset && "adding fields out of order");
15011502

15021503
// Add a padding field if required.
1503-
if (offset != NextOffset)
1504+
if (!isZeroSized && offset != NextOffset)
15041505
addPaddingField(offset);
15051506

1506-
addFieldInfo(swiftField, fieldType);
1507+
addFieldInfo(swiftField, fieldType, isZeroSized);
15071508
}
15081509

15091510
/// Add information to track a value field at the current offset.
1510-
void addFieldInfo(VarDecl *swiftField, const FixedTypeInfo &fieldType) {
1511+
void addFieldInfo(VarDecl *swiftField, const FixedTypeInfo &fieldType, bool isZeroSized) {
15111512
bool isLoadableField = isa<LoadableTypeInfo>(fieldType);
15121513
unsigned explosionSize = 0;
15131514
if (isLoadableField)
@@ -1517,11 +1518,15 @@ class ClangRecordLowering {
15171518
unsigned explosionEnd = NextExplosionIndex;
15181519

15191520
ElementLayout layout = ElementLayout::getIncomplete(fieldType);
1520-
auto isEmpty = fieldType.isKnownEmpty(ResilienceExpansion::Maximal);
1521-
if (isEmpty)
1522-
layout.completeEmptyTailAllocatedCType(
1523-
fieldType.isTriviallyDestroyable(ResilienceExpansion::Maximal), NextOffset);
1524-
else
1521+
auto isEmpty = isZeroSized || fieldType.isKnownEmpty(ResilienceExpansion::Maximal);
1522+
if (isEmpty) {
1523+
if (isZeroSized)
1524+
layout.completeEmpty(
1525+
fieldType.isTriviallyDestroyable(ResilienceExpansion::Maximal), NextOffset);
1526+
else
1527+
layout.completeEmptyTailAllocatedCType(
1528+
fieldType.isTriviallyDestroyable(ResilienceExpansion::Maximal), NextOffset);
1529+
} else
15251530
layout.completeFixed(fieldType.isTriviallyDestroyable(ResilienceExpansion::Maximal),
15261531
NextOffset, LLVMFields.size());
15271532

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

+22
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,26 @@ class MyClass {
66
const int const_member = 23;
77
};
88

9+
struct Empty {
10+
using type = int;
11+
int getNum() const { return 42; }
12+
};
13+
14+
struct HasZeroSizedField {
15+
int a;
16+
[[no_unique_address]] Empty b;
17+
short c;
18+
[[no_unique_address]] Empty d;
19+
int* e;
20+
[[no_unique_address]] Empty f;
21+
22+
int get_a() const { return a; }
23+
short get_c() const { return c; }
24+
void set_c(short c) { this->c = c; }
25+
};
26+
27+
inline int takesZeroSizedInCpp(HasZeroSizedField x) {
28+
return x.a;
29+
}
30+
931
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -enable-experimental-cxx-interop -Xcc -std=c++20)
2+
//
3+
// REQUIRES: executable_test
4+
5+
import StdlibUnittest
6+
import MemberVariables
7+
8+
var FieldsTestSuite = TestSuite("Generating code with zero sized fields")
9+
10+
func takeTypeWithZeroSizedMember(_ x: HasZeroSizedField) {}
11+
12+
FieldsTestSuite.test("Zero sized field") {
13+
var s = HasZeroSizedField()
14+
s.a = 5
15+
s.set_c(7)
16+
takeTypeWithZeroSizedMember(s)
17+
let s2 = s
18+
let myInt : Empty.type = 6
19+
expectEqual(s.a, 5)
20+
expectEqual(s.a, s.get_a())
21+
expectEqual(s2.c, 7)
22+
expectEqual(s2.c, s2.get_c())
23+
expectEqual(takesZeroSizedInCpp(s2), 5)
24+
expectEqual(s.b.getNum(), 42)
25+
}
26+
27+
runAllTests()

0 commit comments

Comments
 (0)
Please sign in to comment.