Skip to content

Commit 13ff3fe

Browse files
authored
Merge pull request #62952 from WANGJIEKE/cxx-interop-enum-associated-value-class-type
[Interop][SwiftToCxx] Add class type support for enum with associated value
2 parents 560781b + b27f35b commit 13ff3fe

File tree

3 files changed

+113
-12
lines changed

3 files changed

+113
-12
lines changed

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -522,18 +522,24 @@ class DeclAndTypePrinter::Implementation
522522
elementDecl->getParentEnum()->getModuleContext());
523523
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
524524
outOfLineOS << ">::type";
525-
outOfLineOS << "::returnNewValue([&](char * _Nonnull result) {\n";
526-
outOfLineOS << " swift::"
527-
<< cxx_synthesis::getCxxImplNamespaceName();
528-
outOfLineOS << "::implClassFor<";
529-
outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded(
530-
objectTypeDecl->getModuleContext(),
531-
elementDecl->getParentEnum()->getModuleContext());
532-
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
533-
outOfLineOS << ">::type";
534-
outOfLineOS
535-
<< "::initializeWithTake(result, payloadFromDestruction);\n";
536-
outOfLineOS << " });\n ";
525+
if (isa<ClassDecl>(objectTypeDecl)) {
526+
outOfLineOS << "::makeRetained(*reinterpret_cast<void "
527+
"**>(payloadFromDestruction));\n ";
528+
} else {
529+
outOfLineOS
530+
<< "::returnNewValue([&](char * _Nonnull result) {\n";
531+
outOfLineOS << " swift::"
532+
<< cxx_synthesis::getCxxImplNamespaceName();
533+
outOfLineOS << "::implClassFor<";
534+
outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded(
535+
objectTypeDecl->getModuleContext(),
536+
elementDecl->getParentEnum()->getModuleContext());
537+
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
538+
outOfLineOS << ">::type";
539+
outOfLineOS << "::initializeWithTake(result, "
540+
"payloadFromDestruction);\n";
541+
outOfLineOS << " });\n ";
542+
}
537543
}
538544
},
539545
ED, ED->getModuleContext(), outOfLineOS);
@@ -666,6 +672,13 @@ class DeclAndTypePrinter::Implementation
666672
outOfLineOS
667673
<< " memcpy(result._getOpaquePointer(), &val, "
668674
"sizeof(val));\n";
675+
} else if (isa<ClassDecl>(objectTypeDecl)) {
676+
outOfLineOS
677+
<< " auto op = swift::"
678+
<< cxx_synthesis::getCxxImplNamespaceName()
679+
<< "::_impl_RefCountedClass::copyOpaquePointer(val);\n";
680+
outOfLineOS << " memcpy(result._getOpaquePointer(), "
681+
"&op, sizeof(op));\n";
669682
} else {
670683
objectTypeDecl =
671684
paramType->getNominalOrBoundGenericNominal();
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend %S/enum-associated-value-class-type-cxx.swift -typecheck -module-name Enums -clang-header-expose-decls=all-public -emit-clang-header-path %t/enums.h
4+
5+
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-enums-execution.o
6+
// RUN: %target-interop-build-swift %S/enum-associated-value-class-type-cxx.swift -o %t/swift-enums-execution -Xlinker %t/swift-enums-execution.o -module-name Enums -Xfrontend -entry-point-function-name -Xfrontend swiftMain
7+
8+
// RUN: %target-codesign %t/swift-enums-execution
9+
// RUN: %target-run %t/swift-enums-execution
10+
11+
// RUN: %empty-directory(%t-evo)
12+
13+
// RUN: %target-swift-frontend %S/enum-associated-value-class-type-cxx.swift -typecheck -module-name Enums -clang-header-expose-decls=all-public -enable-library-evolution -emit-clang-header-path %t-evo/enums.h
14+
15+
// RUN: %target-interop-build-clangxx -c %s -I %t-evo -o %t-evo/swift-enums-execution.o
16+
// RUN: %target-interop-build-swift %S/enum-associated-value-class-type-cxx.swift -o %t-evo/swift-enums-execution -Xlinker %t-evo/swift-enums-execution.o -module-name Enums -enable-library-evolution -Xfrontend -entry-point-function-name -Xfrontend swiftMain
17+
18+
// RUN: %target-codesign %t-evo/swift-enums-execution
19+
// RUN: %target-run %t-evo/swift-enums-execution
20+
21+
// REQUIRES: executable_test
22+
23+
#include <cassert>
24+
#include "enums.h"
25+
26+
using namespace Enums;
27+
28+
extern "C" size_t swift_retainCount(void * _Nonnull obj);
29+
30+
size_t getRetainCount(const C & obj) {
31+
void *p = swift::_impl::_impl_RefCountedClass::getOpaquePointer(obj);
32+
return swift_retainCount(p);
33+
}
34+
35+
int main() {
36+
auto c = C::init(1234);
37+
assert(c.getX() == 1234);
38+
assert(getRetainCount(c) == 1);
39+
40+
{
41+
auto e = E::c(c);
42+
assert(e.isC());
43+
assert(getRetainCount(c) == 2);
44+
45+
auto extracted = e.getC();
46+
assert(getRetainCount(c) == 3);
47+
assert(getRetainCount(extracted) == 3);
48+
assert(extracted.getX() == 1234);
49+
50+
extracted.setX(5678);
51+
assert(extracted.getX() == 5678);
52+
assert(c.getX() == 5678);
53+
}
54+
55+
assert(getRetainCount(c) == 1);
56+
return 0;
57+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -typecheck -module-name Enums -clang-header-expose-decls=all-public -emit-clang-header-path %t/enums.h
3+
// RUN: %FileCheck %s < %t/enums.h
4+
5+
// RUN: %check-interop-cxx-header-in-clang(%t/enums.h -Wno-unused-private-field -Wno-unused-function)
6+
7+
public class C {
8+
public var x: Int
9+
public init(x: Int) { self.x = x }
10+
}
11+
12+
public enum E {
13+
case c(C)
14+
case i(Int)
15+
}
16+
17+
// CHECK: inline E E::_impl_c::operator()(const C& val) const {
18+
// CHECK-NEXT: auto result = E::_make();
19+
// CHECK-NEXT: auto op = swift::_impl::_impl_RefCountedClass::copyOpaquePointer(val);
20+
// CHECK-NEXT: memcpy(result._getOpaquePointer(), &op, sizeof(op));
21+
// CHECK-NEXT: result._destructiveInjectEnumTag(0);
22+
// CHECK-NEXT: return result;
23+
// CHECK-NEXT: }
24+
25+
// CHECK: inline C E::getC() const {
26+
// CHECK-NEXT: if (!isC()) abort();
27+
// CHECK-NEXT: alignas(E) unsigned char buffer[sizeof(E)];
28+
// CHECK-NEXT: auto *thisCopy = new(buffer) E(*this);
29+
// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData();
30+
// CHECK-NEXT: return swift::_impl::implClassFor<C>::type::makeRetained(*reinterpret_cast<void **>(payloadFromDestruction));
31+
// CHECK-NEXT: }

0 commit comments

Comments
 (0)