Skip to content

Commit 8e0278a

Browse files
authored
Merge pull request #60353 from hyp/eng/i/class2
[interop][SwiftToCxx] add support for passing class types to Swift functions
2 parents 8bd4100 + 51c0a3f commit 8e0278a

File tree

5 files changed

+85
-7
lines changed

5 files changed

+85
-7
lines changed

lib/PrintAsClang/PrintClangClassType.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,12 @@ void ClangClassTypePrinter::printClassTypeDecl(
7070
os << "public:\n";
7171
os << "static inline ";
7272
printer.printBaseName(typeDecl);
73-
os << " fromUnretained(void * _Nonnull ptr) noexcept { return ";
73+
os << " makeRetained(void * _Nonnull ptr) noexcept { return ";
7474
printer.printBaseName(typeDecl);
7575
os << "(ptr); }\n";
76+
os << "static inline void * _Nonnull getOpaquePointer(const ";
77+
printer.printBaseName(typeDecl);
78+
os << " &object) noexcept { return object._opaquePointer; }\n";
7679
os << "};\n";
7780
});
7881
}
@@ -85,7 +88,20 @@ void ClangClassTypePrinter::printClassTypeReturnScaffold(
8588
type->getModuleContext(), moduleContext);
8689
os << cxx_synthesis::getCxxImplNamespaceName() << "::";
8790
ClangValueTypePrinter::printCxxImplClassName(os, type);
88-
os << "::fromUnretained(";
91+
os << "::makeRetained(";
8992
bodyPrinter();
9093
os << ");\n";
9194
}
95+
96+
void ClangClassTypePrinter::printParameterCxxtoCUseScaffold(
97+
raw_ostream &os, const ClassDecl *type, const ModuleDecl *moduleContext,
98+
llvm::function_ref<void(void)> bodyPrinter, bool isInOut) {
99+
// FIXME: Handle isInOut
100+
ClangSyntaxPrinter(os).printModuleNamespaceQualifiersIfNeeded(
101+
type->getModuleContext(), moduleContext);
102+
os << cxx_synthesis::getCxxImplNamespaceName() << "::";
103+
ClangValueTypePrinter::printCxxImplClassName(os, type);
104+
os << "::getOpaquePointer(";
105+
bodyPrinter();
106+
os << ')';
107+
}

lib/PrintAsClang/PrintClangClassType.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ class ClangClassTypePrinter {
3737
const ModuleDecl *moduleContext,
3838
llvm::function_ref<void(void)> bodyPrinter);
3939

40+
static void printParameterCxxtoCUseScaffold(
41+
raw_ostream &os, const ClassDecl *type, const ModuleDecl *moduleContext,
42+
llvm::function_ref<void(void)> bodyPrinter, bool isInOut);
43+
4044
private:
4145
raw_ostream &os;
4246
};

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,12 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
459459
return;
460460
}
461461

462+
if (auto *classDecl = type->getClassOrBoundGenericClass()) {
463+
ClangClassTypePrinter::printParameterCxxtoCUseScaffold(
464+
os, classDecl, moduleContext, namePrinter, isInOut);
465+
return;
466+
}
467+
462468
if (auto *decl = type->getNominalOrBoundGenericNominal()) {
463469
if ((isa<StructDecl>(decl) || isa<EnumDecl>(decl))) {
464470
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)

test/Interop/SwiftToCxx/class/swift-class-execution.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,44 @@
1212

1313
#include <assert.h>
1414
#include "class.h"
15+
#include <cstdio>
16+
17+
extern "C" size_t swift_retainCount(void * _Nonnull obj);
18+
19+
size_t getRetainCount(const Class::ClassWithIntField & swiftClass) {
20+
void *p = Class::_impl::_impl_ClassWithIntField::getOpaquePointer(swiftClass);
21+
return swift_retainCount(p);
22+
}
1523

1624
int main() {
1725
using namespace Class;
1826

1927
// Ensure that the class is released.
20-
auto x = returnClassWithIntField();
28+
{
29+
auto x = returnClassWithIntField();
30+
assert(getRetainCount(x) == 1);
31+
}
2132
// CHECK: init ClassWithIntField
33+
// CHECK-NEXT: destroy ClassWithIntField
34+
35+
{
36+
auto x = returnClassWithIntField();
37+
{
38+
takeClassWithIntField(x);
39+
assert(getRetainCount(x) == 1);
40+
auto x2 = passThroughClassWithIntField(x);
41+
assert(getRetainCount(x) == 2);
42+
assert(getRetainCount(x2) == 2);
43+
takeClassWithIntField(x2);
44+
assert(getRetainCount(x) == 2);
45+
}
46+
assert(getRetainCount(x) == 1);
47+
takeClassWithIntField(x);
48+
}
49+
// CHECK-NEXT: init ClassWithIntField
50+
// CHECK-NEXT: ClassWithIntField: 0;
51+
// CHECK-NEXT: ClassWithIntField: 42;
52+
// CHECK-NEXT: ClassWithIntField: 42;
2253
// CHECK-NEXT: destroy ClassWithIntField
2354
return 0;
2455
}

test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// RUN: %check-interop-cxx-header-in-clang(%t/class.h)
66

77
public final class ClassWithIntField {
8-
let field: Int64
8+
var field: Int64
99

1010
init() {
1111
field = 0
@@ -18,7 +18,9 @@ public final class ClassWithIntField {
1818

1919
// CHECK: namespace Class {
2020

21-
// CHECK: SWIFT_EXTERN void * _Nonnull $s5Class06returnA12WithIntFieldAA0acdE0CyF(void) SWIFT_NOEXCEPT SWIFT_CALL; // returnClassWithIntField()
21+
// CHECK: SWIFT_EXTERN void * _Nonnull $s5Class011passThroughA12WithIntFieldyAA0adeF0CADF(void * _Nonnull x) SWIFT_NOEXCEPT SWIFT_CALL; // passThroughClassWithIntField(_:)
22+
// CHECK-NEXT: SWIFT_EXTERN void * _Nonnull $s5Class06returnA12WithIntFieldAA0acdE0CyF(void) SWIFT_NOEXCEPT SWIFT_CALL; // returnClassWithIntField()
23+
// CHECK-NEXT: SWIFT_EXTERN void $s5Class04takeA12WithIntFieldyyAA0acdE0CF(void * _Nonnull x) SWIFT_NOEXCEPT SWIFT_CALL; // takeClassWithIntField(_:)
2224

2325
// CHECK: namespace Class {
2426

@@ -43,11 +45,16 @@ public final class ClassWithIntField {
4345
// CHECK-EMPTY:
4446
// CHECK-NEXT:class _impl_ClassWithIntField {
4547
// CHECK-NEXT:public:
46-
// CHECK-NEXT:static inline ClassWithIntField fromUnretained(void * _Nonnull ptr) noexcept { return ClassWithIntField(ptr); }
48+
// CHECK-NEXT:static inline ClassWithIntField makeRetained(void * _Nonnull ptr) noexcept { return ClassWithIntField(ptr); }
49+
// CHECK-NEXT:static inline void * _Nonnull getOpaquePointer(const ClassWithIntField &object) noexcept { return object._opaquePointer; }
4750
// CHECK-NEXT:};
4851
// CHECK-EMPTY:
4952
// CHECK-NEXT:} // namespace _impl
5053

54+
// CHECK: inline ClassWithIntField passThroughClassWithIntField(const ClassWithIntField& x) noexcept SWIFT_WARN_UNUSED_RESULT {
55+
// CHECK-NEXT: return _impl::_impl_ClassWithIntField::makeRetained(_impl::$s5Class011passThroughA12WithIntFieldyAA0adeF0CADF(_impl::_impl_ClassWithIntField::getOpaquePointer(x)));
56+
// CHECK-NEXT: }
57+
5158
public final class register { }
5259

5360
// CHECK: class register_ final {
@@ -56,6 +63,20 @@ public func returnClassWithIntField() -> ClassWithIntField {
5663
return ClassWithIntField()
5764
}
5865

66+
67+
public func passThroughClassWithIntField(_ x: ClassWithIntField) -> ClassWithIntField {
68+
x.field = 42
69+
return x
70+
}
71+
72+
public func takeClassWithIntField(_ x: ClassWithIntField) {
73+
print("ClassWithIntField: \(x.field);")
74+
}
75+
5976
// CHECK: inline ClassWithIntField returnClassWithIntField() noexcept SWIFT_WARN_UNUSED_RESULT {
60-
// CHECK-NEXT: return _impl::_impl_ClassWithIntField::fromUnretained(_impl::$s5Class06returnA12WithIntFieldAA0acdE0CyF());
77+
// CHECK-NEXT: return _impl::_impl_ClassWithIntField::makeRetained(_impl::$s5Class06returnA12WithIntFieldAA0acdE0CyF());
78+
// CHECK-NEXT: }
79+
80+
// CHECK: inline void takeClassWithIntField(const ClassWithIntField& x) noexcept {
81+
// CHECK-NEXT: return _impl::$s5Class04takeA12WithIntFieldyyAA0acdE0CF(_impl::_impl_ClassWithIntField::getOpaquePointer(x));
6182
// CHECK-NEXT: }

0 commit comments

Comments
 (0)