Skip to content

Commit b787172

Browse files
committed
[interop][SwiftToCxx] emit destructor that calls value witness destroy function for Swift structs
1 parent a65ddbe commit b787172

File tree

4 files changed

+99
-7
lines changed

4 files changed

+99
-7
lines changed

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,13 @@ printCValueTypeStorageStruct(raw_ostream &os, const NominalTypeDecl *typeDecl,
6161
}
6262

6363
void printCTypeMetadataTypeFunction(raw_ostream &os,
64-
const NominalTypeDecl *typeDecl) {
64+
const NominalTypeDecl *typeDecl,
65+
StringRef typeMetadataFuncName) {
6566
os << "// Type metadata accessor for " << typeDecl->getNameStr() << "\n";
66-
auto entity = irgen::LinkEntity::forTypeMetadataAccessFunction(
67-
typeDecl->getDeclaredType()->getCanonicalType());
6867
os << "SWIFT_EXTERN ";
6968
ClangSyntaxPrinter printer(os);
7069
printer.printSwiftImplQualifier();
71-
os << "MetadataResponseTy ";
72-
entity.mangle(os);
73-
os << '(';
70+
os << "MetadataResponseTy " << typeMetadataFuncName << '(';
7471
printer.printSwiftImplQualifier();
7572
os << "MetadataRequestTy)";
7673
os << " SWIFT_NOEXCEPT SWIFT_CALL;\n\n";
@@ -90,6 +87,10 @@ void ClangValueTypePrinter::printStructDecl(const StructDecl *SD) {
9087

9188
ClangSyntaxPrinter printer(os);
9289

90+
auto typeMetadataFunc = irgen::LinkEntity::forTypeMetadataAccessFunction(
91+
SD->getDeclaredType()->getCanonicalType());
92+
std::string typeMetadataFuncName = typeMetadataFunc.mangleAsString();
93+
9394
// Print out a forward declaration of the "hidden" _impl class.
9495
printer.printNamespace(cxx_synthesis::getCxxImplNamespaceName(),
9596
[&](raw_ostream &os) {
@@ -99,13 +100,41 @@ void ClangValueTypePrinter::printStructDecl(const StructDecl *SD) {
99100

100101
// Print out special functions, like functions that
101102
// access type metadata.
102-
printCTypeMetadataTypeFunction(os, SD);
103+
printCTypeMetadataTypeFunction(os, SD,
104+
typeMetadataFuncName);
103105
});
104106

105107
// Print out the C++ class itself.
106108
os << "class ";
107109
ClangSyntaxPrinter(os).printBaseName(SD);
108110
os << " final {\n";
111+
os << "public:\n";
112+
113+
// Print out the destructor.
114+
os << " inline ~";
115+
printer.printBaseName(SD);
116+
os << "() {\n";
117+
os << " auto metadata = " << cxx_synthesis::getCxxImplNamespaceName()
118+
<< "::" << typeMetadataFuncName << "(0);\n";
119+
os << " auto *vwTable = "
120+
"*(reinterpret_cast<swift::_impl::ValueWitnessTable **>(metadata._0) - "
121+
"1);\n";
122+
os << " vwTable->destroy(_getOpaquePointer(), metadata._0);\n";
123+
os << " }\n";
124+
125+
os << " inline ";
126+
printer.printBaseName(SD);
127+
os << "(const ";
128+
printer.printBaseName(SD);
129+
os << " &) = default;\n";
130+
131+
// FIXME: the move constructor should be hidden somehow.
132+
os << " inline ";
133+
printer.printBaseName(SD);
134+
os << "(";
135+
printer.printBaseName(SD);
136+
os << " &&) = default;\n";
137+
109138
// FIXME: Print the other members of the struct.
110139
os << "private:\n";
111140

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend %S/struct-with-refcounted-member.swift -typecheck -module-name Structs -clang-header-expose-public-decls -emit-clang-header-path %t/structs.h
4+
5+
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-structs-execution.o
6+
// RUN: %target-interop-build-swift %S/struct-with-refcounted-member.swift -o %t/swift-structs-execution -Xlinker %t/swift-structs-execution.o -module-name Structs -Xfrontend -entry-point-function-name -Xfrontend swiftMain
7+
8+
// RUN: %target-codesign %t/swift-structs-execution
9+
// RUN: %target-run %t/swift-structs-execution | %FileCheck %s
10+
11+
// REQUIRES: executable_test
12+
13+
#include <assert.h>
14+
#include "structs.h"
15+
16+
int main() {
17+
using namespace Structs;
18+
19+
// Ensure that the value destructor is called.
20+
{
21+
StructWithRefcountedMember value = returnNewStructWithRefcountedMember();
22+
}
23+
// CHECK: create RefCountedClass
24+
// CHECK-NEXT: destroy RefCountedClass
25+
return 0;
26+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -typecheck -module-name Structs -clang-header-expose-public-decls -emit-clang-header-path %t/structs.h
3+
// RUN: %FileCheck %s < %t/structs.h
4+
5+
// RUN: %check-interop-cxx-header-in-clang(%t/structs.h -Wno-unused-function)
6+
7+
class RefCountedClass {
8+
init() {
9+
print("create RefCountedClass")
10+
}
11+
deinit {
12+
print("destroy RefCountedClass")
13+
}
14+
}
15+
16+
public struct StructWithRefcountedMember {
17+
let x: RefCountedClass
18+
}
19+
20+
public func returnNewStructWithRefcountedMember() -> StructWithRefcountedMember {
21+
return StructWithRefcountedMember(x: RefCountedClass())
22+
}
23+
24+
// CHECK: class StructWithRefcountedMember final {
25+
// CHECK-NEXT: public:
26+
// CHECK-NEXT: inline ~StructWithRefcountedMember() {
27+
// CHECK-NEXT: auto metadata = _impl::$s7Structs26StructWithRefcountedMemberVMa(0);
28+
// CHECK-NEXT: auto *vwTable = *(reinterpret_cast<swift::_impl::ValueWitnessTable **>(metadata._0) - 1);
29+
// CHECK-NEXT: vwTable->destroy(_getOpaquePointer(), metadata._0);
30+
// CHECK-NEXT: }
31+
// CHECK-NEXT: inline StructWithRefcountedMember(const StructWithRefcountedMember &) = default;
32+
// CHECK-NEXT: inline StructWithRefcountedMember(StructWithRefcountedMember &&) = default;
33+
// CHECK-NEXT: private:

test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
// CHECK-NEXT: }
2121

2222
// CHECK: class StructWithIntField final {
23+
// CHECK-NEXT: public:
24+
// CHECK-NEXT: inline ~StructWithIntField() {
25+
// CHECK: inline StructWithIntField(const StructWithIntField &) = default;
26+
// CHECK-NEXT: inline StructWithIntField(StructWithIntField &&) = default;
2327
// CHECK-NEXT: private:
2428
// CHECK-NEXT: inline StructWithIntField() {}
2529
// CHECK-NEXT: static inline StructWithIntField _make() { return StructWithIntField(); }

0 commit comments

Comments
 (0)