Skip to content

Commit 9ba29bc

Browse files
authored
Merge pull request #60371 from hyp/eng/i/class-inherit
[interop][SwiftToCxx] map class inheritance to C++ class hierarchy
2 parents a7dadeb + 7c5b160 commit 9ba29bc

File tree

4 files changed

+201
-8
lines changed

4 files changed

+201
-8
lines changed

lib/PrintAsClang/PrintClangClassType.cpp

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

34-
StringRef baseClassName = "RefCountedClass";
35-
StringRef baseClassQualifiedName = "swift::_impl::RefCountedClass";
34+
std::string baseClassName;
35+
std::string baseClassQualifiedName;
36+
37+
if (auto *parentClass = typeDecl->getSuperclassDecl()) {
38+
llvm::raw_string_ostream baseNameOS(baseClassName);
39+
ClangSyntaxPrinter(baseNameOS).printBaseName(parentClass);
40+
llvm::raw_string_ostream baseQualNameOS(baseClassQualifiedName);
41+
ClangSyntaxPrinter(baseQualNameOS)
42+
.printModuleNamespaceQualifiersIfNeeded(parentClass->getModuleContext(),
43+
typeDecl->getModuleContext());
44+
if (!baseQualNameOS.str().empty())
45+
baseQualNameOS << "::";
46+
baseQualNameOS << baseNameOS.str();
47+
} else {
48+
baseClassName = "RefCountedClass";
49+
baseClassQualifiedName = "swift::_impl::RefCountedClass";
50+
}
3651

3752
os << "class ";
3853
printer.printBaseName(typeDecl);
39-
// FIXME: Add support for inherintance.
40-
os << " final : public " << baseClassQualifiedName;
54+
if (typeDecl->isFinal())
55+
os << " final";
56+
os << " : public " << baseClassQualifiedName;
4157
os << " {\n";
4258
os << "public:\n";
4359

4460
os << " using " << baseClassName << "::" << baseClassName << ";\n";
4561
os << " using " << baseClassName << "::operator=;\n";
4662

47-
os << "private:\n";
63+
os << "protected:\n";
4864
os << " inline ";
4965
printer.printBaseName(typeDecl);
5066
os << "(void * _Nonnull ptr) noexcept : " << baseClassName << "(ptr) {}\n";
51-
os << "\n friend class " << cxx_synthesis::getCxxImplNamespaceName() << "::";
67+
os << "private:\n";
68+
os << " friend class " << cxx_synthesis::getCxxImplNamespaceName() << "::";
5269
printCxxImplClassName(os, typeDecl);
5370
os << ";\n";
5471
os << "};\n\n";

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ public final class ClassWithIntField {
3535
// CHECK-NEXT: public:
3636
// CHECK-NEXT: using RefCountedClass::RefCountedClass;
3737
// CHECK-NEXT: using RefCountedClass::operator=;
38-
// CHECK-NEXT: private:
38+
// CHECK-NEXT: protected:
3939
// CHECK-NEXT: inline ClassWithIntField(void * _Nonnull ptr) noexcept : RefCountedClass(ptr) {}
40-
// CHECK-EMPTY:
40+
// CHECK-NEXT: private:
4141
// CHECK-NEXT: friend class _impl::_impl_ClassWithIntField;
4242
// CHECK-NEXT: };
4343
// CHECK-EMPTY:
@@ -84,3 +84,7 @@ public func takeClassWithIntFieldInout(_ x: inout ClassWithIntField) {
8484
// CHECK: inline void takeClassWithIntField(const ClassWithIntField& x) noexcept {
8585
// CHECK-NEXT: return _impl::$s5Class04takeA12WithIntFieldyyAA0acdE0CF(::swift::_impl::_impl_RefCountedClass::getOpaquePointer(x));
8686
// CHECK-NEXT: }
87+
88+
// CHECK: inline void takeClassWithIntFieldInout(ClassWithIntField& x) noexcept {
89+
// CHECK-NEXT: return _impl::$s5Class04takeA17WithIntFieldInoutyyAA0acdE0CzF(&::swift::_impl::_impl_RefCountedClass::getOpaquePointerRef(x));
90+
// CHECK-NEXT: }
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend %S/swift-class-inheritance-in-cxx.swift -typecheck -module-name Class -clang-header-expose-public-decls -emit-clang-header-path %t/class.h
4+
5+
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-class-execution.o
6+
// RUN: %target-interop-build-swift %S/swift-class-inheritance-in-cxx.swift -o %t/swift-class-execution -Xlinker %t/swift-class-execution.o -module-name Class -Xfrontend -entry-point-function-name -Xfrontend swiftMain
7+
8+
// RUN: %target-codesign %t/swift-class-execution
9+
// RUN: %target-run %t/swift-class-execution | %FileCheck %s
10+
11+
// RUN: not %target-interop-build-clangxx -c %s -I %t -o %t/swift-class-execution.o -DERROR1
12+
// RUN: not %target-interop-build-clangxx -c %s -I %t -o %t/swift-class-execution.o -DERROR2
13+
14+
// REQUIRES: executable_test
15+
16+
#include <assert.h>
17+
#include "class.h"
18+
19+
using namespace Class;
20+
21+
int passByValue(BaseClass b) { return 0; }
22+
int passByValue(DerivedClass d) { return 1; }
23+
24+
int passByRef(const BaseClass &b) { return 0; }
25+
int passByRef(const DerivedClass &d){ return 1; }
26+
27+
int passByRef2(const BaseClass &b) { return 0; }
28+
int passByRef2(const DerivedClass &d){ return 1; }
29+
int passByRef2(const DerivedDerivedClass &d){ return 2; }
30+
31+
extern "C" size_t swift_retainCount(void * _Nonnull obj);
32+
33+
size_t getRetainCount(const BaseClass &swiftClass) {
34+
return swift_retainCount(swift::_impl::_impl_RefCountedClass::getOpaquePointer(swiftClass));
35+
}
36+
37+
#ifdef ERROR1
38+
void checkNotCompile1(BaseClass b) {
39+
useDerivedClass(b);
40+
}
41+
#endif
42+
43+
#ifdef ERROR2
44+
void checkNotCompile2(SiblingDerivedClass b) {
45+
DerivedClass c = b;
46+
}
47+
#endif
48+
49+
int main() {
50+
{
51+
auto x = returnDerivedClass();
52+
useBaseClass(x);
53+
useDerivedClass(x);
54+
assert(passByValue(x) == 1);
55+
assert(passByRef(x) == 1);
56+
{
57+
assert(getRetainCount(x) == 1);
58+
BaseClass baseCopy = x;
59+
useBaseClass(baseCopy);
60+
assert(getRetainCount(x) == 2);
61+
baseCopy = x;
62+
assert(getRetainCount(x) == 2);
63+
}
64+
}
65+
// CHECK: init BaseClass
66+
// CHECK-NEXT: init DerivedClass
67+
// CHECK-NEXT: useBaseClass, type=Class.DerivedClass
68+
// CHECK-NEXT: useDerivedClass, type=Class.DerivedClass
69+
// CHECK-NEXT: useBaseClass, type=Class.DerivedClass
70+
// CHECK-NEXT: destroy DerivedClass
71+
// CHECK-NEXT: destroy BaseClass
72+
73+
{
74+
auto x = returnDerivedDerivedClass();
75+
useBaseClass(x);
76+
useDerivedClass(x);
77+
assert(passByValue(x) == 1);
78+
assert(passByRef(x) == 1);
79+
assert(passByRef2(x) == 2);
80+
}
81+
// CHECK-NEXT: init BaseClass
82+
// CHECK-NEXT: init DerivedClass
83+
// CHECK-NEXT: init DerivedDerivedClass
84+
// CHECK-NEXT: useBaseClass, type=Class.DerivedDerivedClass
85+
// CHECK-NEXT: useDerivedClass, type=Class.DerivedDerivedClass
86+
// CHECK-NEXT: destroy DerivedDerivedClass
87+
// CHECK-NEXT: destroy DerivedClass
88+
// CHECK-NEXT: destroy BaseClass
89+
return 0;
90+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -typecheck -module-name Class -clang-header-expose-public-decls -emit-clang-header-path %t/class.h
3+
// RUN: %FileCheck %s < %t/class.h
4+
5+
// RUN: %check-interop-cxx-header-in-clang(%t/class.h)
6+
7+
public class BaseClass {
8+
var field: Int64
9+
10+
init() {
11+
field = 0
12+
print("init BaseClass")
13+
}
14+
deinit {
15+
print("destroy BaseClass")
16+
}
17+
}
18+
public class DerivedClass: BaseClass {
19+
override init() {
20+
super.init()
21+
print("init DerivedClass")
22+
}
23+
deinit {
24+
print("destroy DerivedClass")
25+
}
26+
}
27+
public final class DerivedDerivedClass: DerivedClass {
28+
override init() {
29+
super.init()
30+
print("init DerivedDerivedClass")
31+
}
32+
deinit {
33+
print("destroy DerivedDerivedClass")
34+
}
35+
}
36+
public final class SiblingDerivedClass: BaseClass {
37+
}
38+
39+
public func returnDerivedClass() -> DerivedClass {
40+
return DerivedClass()
41+
}
42+
43+
public func returnDerivedDerivedClass() -> DerivedDerivedClass {
44+
return DerivedDerivedClass()
45+
}
46+
47+
public func useBaseClass(_ x: BaseClass) {
48+
print("useBaseClass, type=\(x.self)")
49+
}
50+
51+
public func useDerivedClass(_ x: DerivedClass) {
52+
print("useDerivedClass, type=\(x.self)")
53+
}
54+
55+
// CHECK: class DerivedClass : public BaseClass {
56+
// CHECK-NEXT: public:
57+
// CHECK-NEXT: using BaseClass::BaseClass;
58+
// CHECK-NEXT: using BaseClass::operator=;
59+
// CHECK-NEXT: protected:
60+
// CHECK-NEXT: inline DerivedClass(void * _Nonnull ptr) noexcept : BaseClass(ptr) {}
61+
// CHECK-NEXT: private:
62+
// CHECK-NEXT: friend class _impl::_impl_DerivedClass;
63+
// CHECK-NEXT: };
64+
65+
// CHECK: class DerivedDerivedClass final : public DerivedClass {
66+
// CHECK-NEXT: public:
67+
// CHECK-NEXT: using DerivedClass::DerivedClass;
68+
// CHECK-NEXT: using DerivedClass::operator=;
69+
// CHECK-NEXT: protected:
70+
// CHECK-NEXT: inline DerivedDerivedClass(void * _Nonnull ptr) noexcept : DerivedClass(ptr) {}
71+
// CHECK-NEXT: private:
72+
// CHECK-NEXT: friend class _impl::_impl_DerivedDerivedClass;
73+
// CHECK-NEXT: };
74+
75+
// Verify base class names are adjusted to avoid conflict with C++ keywords.
76+
public class auto {}
77+
public class derivedRegister: auto {}
78+
79+
// CHECK: class derivedRegister : public auto_ {
80+
// CHECK: using auto_::auto_;
81+
// CHECK: using auto_::operator=;
82+
// CHECK: inline derivedRegister(void * _Nonnull ptr) noexcept : auto_(ptr) {}

0 commit comments

Comments
 (0)