Skip to content

Commit 09dcbde

Browse files
authored
Merge pull request #60359 from hyp/eng/i/class3
[interop][SwiftToCxx] copy construct & assign should do ARC operations for class reference values
2 parents db7d1e7 + 478987b commit 09dcbde

File tree

6 files changed

+123
-38
lines changed

6 files changed

+123
-38
lines changed

lib/PrintAsClang/PrintClangClassType.cpp

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,32 +31,24 @@ void ClangClassTypePrinter::printClassTypeDecl(
3131
os << ";\n";
3232
});
3333

34+
StringRef baseClassName = "RefCountedClass";
35+
StringRef baseClassQualifiedName = "swift::_impl::RefCountedClass";
36+
3437
os << "class ";
3538
printer.printBaseName(typeDecl);
3639
// FIXME: Add support for inherintance.
37-
os << " final";
40+
os << " final : public " << baseClassQualifiedName;
3841
os << " {\n";
3942
os << "public:\n";
4043

41-
// Destructor releases the object.
42-
os << " inline ~";
43-
printer.printBaseName(typeDecl);
44-
os << "() { swift::" << cxx_synthesis::getCxxImplNamespaceName()
45-
<< "::swift_release(_opaquePointer); }\n";
46-
47-
// FIXME: move semantics should be restricted?
48-
os << " inline ";
49-
printer.printBaseName(typeDecl);
50-
os << "(";
51-
printer.printBaseName(typeDecl);
52-
os << "&&) noexcept = default;\n";
44+
os << " using " << baseClassName << "::" << baseClassName << ";\n";
45+
os << " using " << baseClassName << "::operator=;\n";
5346

5447
os << "private:\n";
5548
os << " inline ";
5649
printer.printBaseName(typeDecl);
57-
os << "(void * _Nonnull ptr) noexcept : _opaquePointer(ptr) {}\n";
58-
os << "\n void * _Nonnull _opaquePointer;\n";
59-
os << " friend class " << cxx_synthesis::getCxxImplNamespaceName() << "::";
50+
os << "(void * _Nonnull ptr) noexcept : " << baseClassName << "(ptr) {}\n";
51+
os << "\n friend class " << cxx_synthesis::getCxxImplNamespaceName() << "::";
6052
printCxxImplClassName(os, typeDecl);
6153
os << ";\n";
6254
os << "};\n\n";
@@ -73,9 +65,6 @@ void ClangClassTypePrinter::printClassTypeDecl(
7365
os << " makeRetained(void * _Nonnull ptr) noexcept { return ";
7466
printer.printBaseName(typeDecl);
7567
os << "(ptr); }\n";
76-
os << "static inline void * _Nonnull getOpaquePointer(const ";
77-
printer.printBaseName(typeDecl);
78-
os << " &object) noexcept { return object._opaquePointer; }\n";
7968
os << "};\n";
8069
});
8170
}
@@ -96,12 +85,14 @@ void ClangClassTypePrinter::printClassTypeReturnScaffold(
9685
void ClangClassTypePrinter::printParameterCxxtoCUseScaffold(
9786
raw_ostream &os, const ClassDecl *type, const ModuleDecl *moduleContext,
9887
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(";
88+
if (isInOut)
89+
os << '&';
90+
os << "::swift::" << cxx_synthesis::getCxxImplNamespaceName()
91+
<< "::_impl_RefCountedClass"
92+
<< "::getOpaquePointer";
93+
if (isInOut)
94+
os << "Ref";
95+
os << '(';
10596
bodyPrinter();
10697
os << ')';
10798
}

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,13 @@ class CFunctionSignatureTypePrinter
151151
void visitClassType(ClassType *CT, Optional<OptionalTypeKind> optionalKind,
152152
bool isInOutParam) {
153153
// FIXME: handle optionalKind.
154-
// FIXME: handle isInOutParam.
155154
if (languageMode != OutputLanguageMode::Cxx) {
156155
os << "void * _Nonnull";
156+
if (isInOutParam)
157+
os << " * _Nonnull";
157158
return;
158159
}
159-
if (typeUseKind == FunctionSignatureTypeUse::ParamType)
160+
if (typeUseKind == FunctionSignatureTypeUse::ParamType && !isInOutParam)
160161
os << "const ";
161162
ClangSyntaxPrinter(os).printBaseName(CT->getDecl());
162163
if (typeUseKind == FunctionSignatureTypeUse::ParamType)

stdlib/public/SwiftShims/_SwiftCxxInteroperability.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,41 @@ inline void opaqueFree(void *_Nonnull p) noexcept {
5353
#endif
5454
}
5555

56+
/// Base class for a Swift reference counted class value.
57+
class RefCountedClass {
58+
public:
59+
inline ~RefCountedClass() { swift_release(_opaquePointer); }
60+
inline RefCountedClass(const RefCountedClass &other) noexcept
61+
: _opaquePointer(other._opaquePointer) {
62+
swift_retain(_opaquePointer);
63+
}
64+
inline RefCountedClass &operator=(const RefCountedClass &other) noexcept {
65+
swift_retain(other._opaquePointer);
66+
swift_release(_opaquePointer);
67+
_opaquePointer = other._opaquePointer;
68+
return *this;
69+
}
70+
// FIXME: What to do in 'move'?
71+
inline RefCountedClass(RefCountedClass &&) noexcept = default;
72+
73+
protected:
74+
inline RefCountedClass(void *_Nonnull ptr) noexcept : _opaquePointer(ptr) {}
75+
76+
private:
77+
void *_Nonnull _opaquePointer;
78+
friend class _impl_RefCountedClass;
79+
};
80+
81+
class _impl_RefCountedClass {
82+
public:
83+
static inline void *_Nonnull getOpaquePointer(const RefCountedClass &object) {
84+
return object._opaquePointer;
85+
}
86+
static inline void *_Nonnull &getOpaquePointerRef(RefCountedClass &object) {
87+
return object._opaquePointer;
88+
}
89+
};
90+
5691
} // namespace _impl
5792

5893
/// Swift's Int type.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend %S/swift-class-in-cxx.swift -typecheck -module-name Class -clang-header-expose-public-decls -emit-clang-header-path %t/class.h
4+
5+
// RUN: not %target-interop-build-clangxx -c %s -I %t -o %t/swift-class-execution.o
6+
7+
#include "class.h"
8+
9+
void test(void * _Nonnull p) {
10+
// Prohibited to construct class reference directly from opaque pointer.
11+
Class::ClassWithIntField x(p);
12+
}

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

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
extern "C" size_t swift_retainCount(void * _Nonnull obj);
1818

1919
size_t getRetainCount(const Class::ClassWithIntField & swiftClass) {
20-
void *p = Class::_impl::_impl_ClassWithIntField::getOpaquePointer(swiftClass);
21-
return swift_retainCount(p);
20+
void *p = swift::_impl::_impl_RefCountedClass::getOpaquePointer(swiftClass);
21+
return swift_retainCount(p);
2222
}
2323

2424
int main() {
@@ -50,6 +50,48 @@ int main() {
5050
// CHECK-NEXT: ClassWithIntField: 0;
5151
// CHECK-NEXT: ClassWithIntField: 42;
5252
// CHECK-NEXT: ClassWithIntField: 42;
53+
// CHECK-NEXT: destroy ClassWithIntField
54+
55+
{
56+
auto x = returnClassWithIntField();
57+
assert(getRetainCount(x) == 1);
58+
takeClassWithIntFieldInout(x);
59+
assert(getRetainCount(x) == 1);
60+
takeClassWithIntField(x);
61+
}
62+
// CHECK-NEXT: init ClassWithIntField
63+
// CHECK-NEXT: init ClassWithIntField
64+
// CHECK-NEXT: destroy ClassWithIntField
65+
// CHECK-NEXT: ClassWithIntField: -11;
66+
// CHECK-NEXT: destroy ClassWithIntField
67+
68+
{
69+
auto x = returnClassWithIntField();
70+
{
71+
auto x2 = x;
72+
assert(getRetainCount(x) == 2);
73+
}
74+
assert(getRetainCount(x) == 1);
75+
}
76+
// CHECK-NEXT: init ClassWithIntField
77+
// CHECK-NEXT: destroy ClassWithIntField
78+
79+
{
80+
auto x = returnClassWithIntField();
81+
{
82+
auto x2 = returnClassWithIntField();
83+
assert(getRetainCount(x2) == 1);
84+
assert(getRetainCount(x) == 1);
85+
x = x2;
86+
assert(getRetainCount(x) == 2);
87+
}
88+
takeClassWithIntField(x);
89+
assert(getRetainCount(x) == 1);
90+
}
91+
// CHECK-NEXT: init ClassWithIntField
92+
// CHECK-NEXT: init ClassWithIntField
93+
// CHECK-NEXT: destroy ClassWithIntField
94+
// CHECK-NEXT: ClassWithIntField: 0;
5395
// CHECK-NEXT: destroy ClassWithIntField
5496
return 0;
5597
}

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

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public final class ClassWithIntField {
2121
// CHECK: SWIFT_EXTERN void * _Nonnull $s5Class011passThroughA12WithIntFieldyAA0adeF0CADF(void * _Nonnull x) SWIFT_NOEXCEPT SWIFT_CALL; // passThroughClassWithIntField(_:)
2222
// CHECK-NEXT: SWIFT_EXTERN void * _Nonnull $s5Class06returnA12WithIntFieldAA0acdE0CyF(void) SWIFT_NOEXCEPT SWIFT_CALL; // returnClassWithIntField()
2323
// CHECK-NEXT: SWIFT_EXTERN void $s5Class04takeA12WithIntFieldyyAA0acdE0CF(void * _Nonnull x) SWIFT_NOEXCEPT SWIFT_CALL; // takeClassWithIntField(_:)
24+
// CHECK-NEXT: SWIFT_EXTERN void $s5Class04takeA17WithIntFieldInoutyyAA0acdE0CzF(void * _Nonnull * _Nonnull x) SWIFT_NOEXCEPT SWIFT_CALL; // takeClassWithIntFieldInout(_:)
2425

2526
// CHECK: namespace Class {
2627

@@ -30,14 +31,13 @@ public final class ClassWithIntField {
3031
// CHECK-EMPTY:
3132
// CHECK-NEXT: } // namespace _impl
3233
// CHECK-EMPTY:
33-
// CHECK-NEXT: class ClassWithIntField final {
34+
// CHECK-NEXT: class ClassWithIntField final : public swift::_impl::RefCountedClass {
3435
// CHECK-NEXT: public:
35-
// CHECK-NEXT: inline ~ClassWithIntField() { swift::_impl::swift_release(_opaquePointer); }
36-
// CHECK-NEXT: inline ClassWithIntField(ClassWithIntField&&) noexcept = default;
36+
// CHECK-NEXT: using RefCountedClass::RefCountedClass;
37+
// CHECK-NEXT: using RefCountedClass::operator=;
3738
// CHECK-NEXT: private:
38-
// CHECK-NEXT: inline ClassWithIntField(void * _Nonnull ptr) noexcept : _opaquePointer(ptr) {}
39+
// CHECK-NEXT: inline ClassWithIntField(void * _Nonnull ptr) noexcept : RefCountedClass(ptr) {}
3940
// CHECK-EMPTY:
40-
// CHECK-NEXT: void * _Nonnull _opaquePointer;
4141
// CHECK-NEXT: friend class _impl::_impl_ClassWithIntField;
4242
// CHECK-NEXT: };
4343
// CHECK-EMPTY:
@@ -46,18 +46,17 @@ public final class ClassWithIntField {
4646
// CHECK-NEXT:class _impl_ClassWithIntField {
4747
// CHECK-NEXT:public:
4848
// 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; }
5049
// CHECK-NEXT:};
5150
// CHECK-EMPTY:
5251
// CHECK-NEXT:} // namespace _impl
5352

5453
// 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)));
54+
// CHECK-NEXT: return _impl::_impl_ClassWithIntField::makeRetained(_impl::$s5Class011passThroughA12WithIntFieldyAA0adeF0CADF(::swift::_impl::_impl_RefCountedClass::getOpaquePointer(x)));
5655
// CHECK-NEXT: }
5756

5857
public final class register { }
5958

60-
// CHECK: class register_ final {
59+
// CHECK: class register_ final : public swift::_impl::RefCountedClass {
6160

6261
public func returnClassWithIntField() -> ClassWithIntField {
6362
return ClassWithIntField()
@@ -73,10 +72,15 @@ public func takeClassWithIntField(_ x: ClassWithIntField) {
7372
print("ClassWithIntField: \(x.field);")
7473
}
7574

75+
public func takeClassWithIntFieldInout(_ x: inout ClassWithIntField) {
76+
x = ClassWithIntField()
77+
x.field = -11
78+
}
79+
7680
// CHECK: inline ClassWithIntField returnClassWithIntField() noexcept SWIFT_WARN_UNUSED_RESULT {
7781
// CHECK-NEXT: return _impl::_impl_ClassWithIntField::makeRetained(_impl::$s5Class06returnA12WithIntFieldAA0acdE0CyF());
7882
// CHECK-NEXT: }
7983

8084
// CHECK: inline void takeClassWithIntField(const ClassWithIntField& x) noexcept {
81-
// CHECK-NEXT: return _impl::$s5Class04takeA12WithIntFieldyyAA0acdE0CF(_impl::_impl_ClassWithIntField::getOpaquePointer(x));
85+
// CHECK-NEXT: return _impl::$s5Class04takeA12WithIntFieldyyAA0acdE0CF(::swift::_impl::_impl_RefCountedClass::getOpaquePointer(x));
8286
// CHECK-NEXT: }

0 commit comments

Comments
 (0)