Skip to content

Commit 762e0ba

Browse files
authored
Merge pull request #61217 from zoecarver/base-classes-as-fields
[cxx-interop] Add base classes as opaque fields when lowering in IRGen.
2 parents 1f8a5d6 + 63c4758 commit 762e0ba

File tree

4 files changed

+63
-131
lines changed

4 files changed

+63
-131
lines changed

lib/IRGen/GenStruct.cpp

Lines changed: 24 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -354,37 +354,6 @@ namespace {
354354
}
355355
}
356356

357-
template <class Fn>
358-
void forEachNonEmptyBaseTypeInfo(Fn fn) const {
359-
forEachNonEmptyBase([&](clang::QualType, clang::CharUnits,
360-
clang::CharUnits size) {
361-
auto &typeInfo = IGM.getOpaqueStorageTypeInfo(Size(size.getQuantity()),
362-
Alignment(1));
363-
fn(typeInfo);
364-
});
365-
}
366-
367-
template <class Fn>
368-
void forEachNonEmptyBaseTypeInfoAndBaseAddress(IRGenFunction &IGF,
369-
Address addr, Fn fn) const {
370-
forEachNonEmptyBase([&](clang::QualType,
371-
clang::CharUnits offset, clang::CharUnits size) {
372-
auto &typeInfo = IGM.getOpaqueStorageTypeInfo(Size(size.getQuantity()),
373-
Alignment(1));
374-
375-
Address baseAddr = addr;
376-
if (offset.getQuantity() != 0) {
377-
auto baseAddrVal =
378-
IGF.Builder.CreateBitCast(addr.getAddress(), IGF.IGM.Int8PtrTy);
379-
baseAddrVal = IGF.Builder.CreateConstGEP1_64(
380-
IGF.IGM.Int8Ty, baseAddrVal, offset.getQuantity());
381-
baseAddr = Address(baseAddrVal, Alignment(1));
382-
}
383-
384-
fn(typeInfo, baseAddr);
385-
});
386-
}
387-
388357
public:
389358
LoadableClangRecordTypeInfo(ArrayRef<ClangFieldInfo> fields,
390359
unsigned explosionSize, IRGenModule &IGM,
@@ -437,106 +406,6 @@ namespace {
437406
lowering.addTypedData(ClangDecl, offset.asCharUnits());
438407
}
439408

440-
void getSchema(ExplosionSchema &schema) const override {
441-
forEachNonEmptyBaseTypeInfo([&](const LoadableTypeInfo &typeInfo) {
442-
typeInfo.getSchema(schema);
443-
});
444-
445-
for (auto &field : getFields()) {
446-
field.getTypeInfo().getSchema(schema);
447-
}
448-
}
449-
450-
void projectFieldFromExplosion(IRGenFunction &IGF, Explosion &in,
451-
VarDecl *field,
452-
Explosion &out) const override {
453-
auto &fieldInfo = getFieldInfo(field);
454-
455-
// If the field requires no storage, there's nothing to do.
456-
if (fieldInfo.isEmpty())
457-
return;
458-
459-
unsigned baseOffset = 0;
460-
if (auto cxxRecord = dyn_cast<clang::CXXRecordDecl>(ClangDecl)) {
461-
baseOffset = llvm::count_if(cxxRecord->bases(), [](auto base) {
462-
auto baseType = base.getType().getCanonicalType();
463-
464-
auto baseRecord = cast<clang::RecordType>(baseType)->getDecl();
465-
auto baseCxxRecord = cast<clang::CXXRecordDecl>(baseRecord);
466-
467-
return !baseCxxRecord->isEmpty();
468-
});
469-
}
470-
471-
// Otherwise, project from the base.
472-
auto fieldRange = fieldInfo.getProjectionRange();
473-
auto elements = in.getRange(fieldRange.first + baseOffset,
474-
fieldRange.second + baseOffset);
475-
out.add(elements);
476-
}
477-
478-
void reexplode(IRGenFunction &IGF, Explosion &src,
479-
Explosion &dest) const override {
480-
forEachNonEmptyBaseTypeInfo([&](const LoadableTypeInfo &typeInfo) {
481-
typeInfo.reexplode(IGF, src, dest);
482-
});
483-
484-
for (auto &field : getFields()) {
485-
cast<LoadableTypeInfo>(field.getTypeInfo()).reexplode(IGF, src, dest);
486-
}
487-
}
488-
489-
void initialize(IRGenFunction &IGF, Explosion &e, Address addr,
490-
bool isOutlined) const override {
491-
forEachNonEmptyBaseTypeInfoAndBaseAddress(
492-
IGF, addr, [&](const LoadableTypeInfo &typeInfo, Address baseAddr) {
493-
typeInfo.initialize(IGF, e, baseAddr, isOutlined);
494-
});
495-
496-
for (auto &field : getFields()) {
497-
if (field.isEmpty())
498-
continue;
499-
500-
Address fieldAddr = field.projectAddress(IGF, addr, None);
501-
cast<LoadableTypeInfo>(field.getTypeInfo())
502-
.initialize(IGF, e, fieldAddr, isOutlined);
503-
}
504-
}
505-
506-
void loadAsTake(IRGenFunction &IGF, Address addr,
507-
Explosion &e) const override {
508-
forEachNonEmptyBaseTypeInfoAndBaseAddress(
509-
IGF, addr, [&](const LoadableTypeInfo &typeInfo, Address baseAddr) {
510-
typeInfo.loadAsTake(IGF, baseAddr, e);
511-
});
512-
513-
for (auto &field : getFields()) {
514-
if (field.isEmpty())
515-
continue;
516-
517-
Address fieldAddr = field.projectAddress(IGF, addr, None);
518-
cast<LoadableTypeInfo>(field.getTypeInfo())
519-
.loadAsTake(IGF, fieldAddr, e);
520-
}
521-
}
522-
523-
void loadAsCopy(IRGenFunction &IGF, Address addr,
524-
Explosion &e) const override {
525-
forEachNonEmptyBaseTypeInfoAndBaseAddress(
526-
IGF, addr, [&](const LoadableTypeInfo &typeInfo, Address baseAddr) {
527-
typeInfo.loadAsCopy(IGF, baseAddr, e);
528-
});
529-
530-
for (auto &field : getFields()) {
531-
if (field.isEmpty())
532-
continue;
533-
534-
Address fieldAddr = field.projectAddress(IGF, addr, None);
535-
cast<LoadableTypeInfo>(field.getTypeInfo())
536-
.loadAsCopy(IGF, fieldAddr, e);
537-
}
538-
}
539-
540409
llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF) const {
541410
return None;
542411
}
@@ -1168,6 +1037,7 @@ class ClangRecordLowering {
11681037
if (ClangDecl->isUnion()) {
11691038
collectUnionFields();
11701039
} else {
1040+
collectBases();
11711041
collectStructFields();
11721042
}
11731043
}
@@ -1195,6 +1065,29 @@ class ClangRecordLowering {
11951065
return (swiftField->getClangNode().castAsDecl() == clangField);
11961066
}
11971067

1068+
void collectBases() {
1069+
auto &layout = ClangDecl->getASTContext().getASTRecordLayout(ClangDecl);
1070+
1071+
if (auto cxxRecord = dyn_cast<clang::CXXRecordDecl>(ClangDecl)) {
1072+
for (auto base : cxxRecord->bases()) {
1073+
if (base.isVirtual())
1074+
continue;
1075+
1076+
auto baseType = base.getType().getCanonicalType();
1077+
1078+
auto baseRecord = cast<clang::RecordType>(baseType)->getDecl();
1079+
auto baseCxxRecord = cast<clang::CXXRecordDecl>(baseRecord);
1080+
1081+
if (baseCxxRecord->isEmpty())
1082+
continue;
1083+
1084+
auto offset = layout.getBaseClassOffset(baseCxxRecord);
1085+
auto size = ClangDecl->getASTContext().getTypeSizeInChars(baseType);
1086+
addOpaqueField(Size(offset.getQuantity()), Size(size.getQuantity()));
1087+
}
1088+
}
1089+
}
1090+
11981091
void collectStructFields() {
11991092
auto cfi = ClangDecl->field_begin(), cfe = ClangDecl->field_end();
12001093
auto swiftProperties = SwiftDecl->getStoredProperties();

test/Interop/Cxx/class/inheritance/Inputs/fields.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ struct DerivedFromAll : HasOneField, DerivedWithOneField {
1616
int f = 6;
1717
};
1818

19+
struct OneField {
20+
int value = 42;
21+
};
22+
23+
struct DerivedFromOneField : OneField {};
24+
1925
// Non trivial types:
2026

2127
struct __attribute__((swift_attr("import_unsafe"))) NonTrivial {

test/Interop/Cxx/class/inheritance/fields-module-interface.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@
3232
// CHECK-NEXT: var c: Int32
3333
// CHECK-NEXT: }
3434

35+
// CHECK-NEXT: struct OneField {
36+
// CHECK-NEXT: init()
37+
// CHECK-NEXT: init(value: Int32)
38+
// CHECK-NEXT: var value: Int32
39+
// CHECK-NEXT: }
40+
// CHECK-NEXT: struct DerivedFromOneField {
41+
// CHECK-NEXT: init()
42+
// CHECK-NEXT: var value: Int32
43+
// CHECK-NEXT: }
44+
3545
// CHECK-NEXT: struct NonTrivial {
3646
// CHECK-NEXT: init()
3747
// CHECK-NEXT: }

test/Interop/Cxx/class/inheritance/fields.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ import Fields
1010

1111
var FieldsTestSuite = TestSuite("Getting and setting fields in base classes")
1212

13+
struct SwiftStructWrapper {
14+
let value: DerivedFromOneField
15+
}
16+
17+
func optionalDerivedFromAll() -> DerivedFromAll? { DerivedFromAll() }
18+
1319
FieldsTestSuite.test("Fields from derived from all") {
1420
let derived = DerivedFromAll()
1521
expectEqual(derived.a, 1)
@@ -31,6 +37,23 @@ FieldsTestSuite.test("Fields from derived from all") {
3137
expectEqual(mutable.f, 48)
3238
}
3339

40+
FieldsTestSuite.test("Optional") {
41+
let derived = optionalDerivedFromAll()
42+
expectEqual(derived!.a, 1)
43+
expectEqual(derived!.b, 2)
44+
expectEqual(derived!.c, 3)
45+
expectEqual(derived!.d, 4)
46+
expectEqual(derived!.e, 5)
47+
expectEqual(derived!.f, 6)
48+
}
49+
50+
FieldsTestSuite.test("Struct holding derived from one field") {
51+
let derived = DerivedFromOneField()
52+
let s = SwiftStructWrapper(value: derived)
53+
54+
expectEqual(s.value.value, 42)
55+
}
56+
3457
FieldsTestSuite.test("Fields from derived from non trivial") {
3558
let derived = NonTrivialDerivedFromAll()
3659
expectEqual(derived.a, 1)

0 commit comments

Comments
 (0)