Skip to content

Commit 0dcb8b5

Browse files
committed
[interop][SwiftToCxx] use C++ types bridged to Swift in Swift generic context from C++ ♾
1 parent 26e5742 commit 0dcb8b5

File tree

4 files changed

+77
-6
lines changed

4 files changed

+77
-6
lines changed

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ class ClangTypeHandler {
109109
ClangSyntaxPrinter(os).printNominalClangTypeReference(typeDecl);
110110
}
111111

112+
static void
113+
printGenericReturnScaffold(raw_ostream &os, StringRef templateParamName,
114+
llvm::function_ref<void(StringRef)> bodyOfReturn) {
115+
printReturnScaffold(nullptr, os, templateParamName, templateParamName,
116+
bodyOfReturn);
117+
}
118+
112119
void printReturnScaffold(raw_ostream &os,
113120
llvm::function_ref<void(StringRef)> bodyOfReturn) {
114121
std::string fullQualifiedType;
@@ -119,14 +126,22 @@ class ClangTypeHandler {
119126
llvm::raw_string_ostream unqualTypeNameOS(typeName);
120127
unqualTypeNameOS << cast<clang::NamedDecl>(typeDecl)->getName();
121128
}
129+
printReturnScaffold(typeDecl, os, fullQualifiedType, typeName,
130+
bodyOfReturn);
131+
}
132+
133+
private:
134+
static void
135+
printReturnScaffold(const clang::Decl *typeDecl, raw_ostream &os,
136+
StringRef fullQualifiedType, StringRef typeName,
137+
llvm::function_ref<void(StringRef)> bodyOfReturn) {
122138
os << "alignas(alignof(" << fullQualifiedType << ")) char storage[sizeof("
123139
<< fullQualifiedType << ")];\n";
124140
os << "auto * _Nonnull storageObjectPtr = reinterpret_cast<"
125141
<< fullQualifiedType << " *>(storage);\n";
126142
bodyOfReturn("storage");
127143
os << ";\n";
128-
auto *cxxRecord = cast<clang::CXXRecordDecl>(typeDecl);
129-
if (cxxRecord->isTrivial()) {
144+
if (typeDecl && cast<clang::CXXRecordDecl>(typeDecl)->isTrivial()) {
130145
// Trivial object can be just copied and not destroyed.
131146
os << "return *storageObjectPtr;\n";
132147
return;
@@ -136,7 +151,6 @@ class ClangTypeHandler {
136151
os << "return result;\n";
137152
}
138153

139-
private:
140154
const clang::Decl *typeDecl;
141155
};
142156

@@ -999,6 +1013,11 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
9991013
<< ">::type::returnNewValue([&](void * _Nonnull returnValue) {\n";
10001014
printCallToCFunc(/*additionalParam=*/StringRef("returnValue"));
10011015
os << ";\n });\n";
1016+
os << " } else if constexpr (::swift::"
1017+
<< cxx_synthesis::getCxxImplNamespaceName()
1018+
<< "::isSwiftBridgedCxxRecord<" << resultTyName << ">) {\n";
1019+
ClangTypeHandler::printGenericReturnScaffold(os, resultTyName,
1020+
printCallToCFunc);
10021021
os << " } else {\n";
10031022
os << " " << resultTyName << " returnValue;\n";
10041023
printCallToCFunc(/*additionalParam=*/StringRef(ros.str()));

test/Interop/CxxToSwiftToCxx/bridge-cxx-struct-back-to-cxx-execution.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
// RUN: %target-swift-frontend -typecheck %t/use-cxx-types.swift -typecheck -module-name UseCxx -emit-clang-header-path %t/UseCxx.h -I %t -enable-experimental-cxx-interop -clang-header-expose-public-decls
55

6-
// RUN: %target-interop-build-clangxx -c %t/use-swift-cxx-types.cpp -I %t -o %t/swift-cxx-execution.o -g
6+
// RUN: %target-interop-build-clangxx -std=c++20 -c %t/use-swift-cxx-types.cpp -I %t -o %t/swift-cxx-execution.o -g
77
// RUN: %target-interop-build-swift %t/use-cxx-types.swift -o %t/swift-cxx-execution -Xlinker %t/swift-cxx-execution.o -module-name UseCxx -Xfrontend -entry-point-function-name -Xfrontend swiftMain -I %t -g
88

99
// RUN: %target-codesign %t/swift-cxx-execution
@@ -80,6 +80,14 @@ public func inoutTrivial(_ x: inout Trivial) {
8080
x.x = x.y + x.x - 11
8181
}
8282

83+
public func takeGeneric<T>(_ x: T) {
84+
print("GENERIC", x)
85+
}
86+
87+
public func retPassThroughGeneric<T>(_ x: T) -> T {
88+
return x
89+
}
90+
8391
//--- use-swift-cxx-types.cpp
8492

8593
#include "header.h"
@@ -98,8 +106,15 @@ int main() {
98106
assert(x.x == -11);
99107
assert(x.y == -423421);
100108
UseCxx::takeTrivial(x);
109+
UseCxx::takeGeneric(x);
110+
auto xPrime = UseCxx::retPassThroughGeneric(x);
111+
assert(xPrime.x == -11);
112+
assert(xPrime.y == -423421);
113+
UseCxx::takeTrivial(xPrime);
101114
}
102115
// CHECK: Trivial(x: 423421, y: -423421)
116+
// CHECK-NEXT: Trivial(x: -11, y: -423421)
117+
// CHECK-NEXT: GENERIC Trivial(x: -11, y: -423421)
103118
// CHECK-NEXT: Trivial(x: -11, y: -423421)
104119
{
105120
auto x = UseCxx::retNonTrivial(-942);
@@ -110,7 +125,16 @@ int main() {
110125
UseCxx::inoutNonTrivial(x);
111126
assert(x.x.y == -1884);
112127
assert(x.x.x == 42);
128+
UseCxx::takeGeneric(x);
129+
{
130+
auto xPrime = UseCxx::retPassThroughGeneric(x);
131+
assert(xPrime.x.y == -1884);
132+
assert(xPrime.x.x == 42);
133+
UseCxx::takeNonTrivial(xPrime);
134+
}
135+
puts("secondon non trivial");
113136
}
137+
puts("EndOfTest");
114138
// CHECK-NEXT: create NonTrivialTemplate
115139
// CHECK-NEXT: move NonTrivialTemplate
116140
// CHECK-NEXT: ~NonTrivialTemplate
@@ -122,6 +146,18 @@ int main() {
122146
// CHECK-NEXT: ~NonTrivialTemplate
123147
// CHECK-NEXT: ~NonTrivialTemplate
124148
// CHECK-NEXT: done non trivial
149+
// CHECK-NEXT: copy NonTrivialTemplate
150+
// CHECK-NEXT: GENERIC __CxxTemplateInst18NonTrivialTemplateI7TrivialE(x: __C.Trivial(x: 42, y: -1884))
151+
// CHECK-NEXT: ~NonTrivialTemplate
152+
// CHECK-NEXT: copy NonTrivialTemplate
153+
// CHECK-NEXT: move NonTrivialTemplate
154+
// CHECK-NEXT: ~NonTrivialTemplate
155+
// CHECK-NEXT: copy NonTrivialTemplate
156+
// CHECK-NEXT: __CxxTemplateInst18NonTrivialTemplateI7TrivialE(x: __C.Trivial(x: 42, y: -1884))
157+
// CHECK-NEXT: ~NonTrivialTemplate
158+
// CHECK-NEXT: ~NonTrivialTemplate
159+
// CHECK-NEXT: secondon non trivial
125160
// CHECK-NEXT: ~NonTrivialTemplate
161+
// CHECK-NEXT: EndOfTest
126162
return 0;
127163
}

test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,13 @@ public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct {
150150
// CHECK-NEXT: return ::swift::_impl::implClassFor<T_0_0>::type::returnNewValue([&](void * _Nonnull returnValue) {
151151
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(returnValue, swift::_impl::getOpaquePointer(x), swift::TypeMetadataTrait<T_0_0>::getTypeMetadata());
152152
// CHECK-NEXT: });
153+
// CHECK-NEXT: } else if constexpr (::swift::_impl::isSwiftBridgedCxxRecord<T_0_0>) {
154+
// CHECK-NEXT: alignas(alignof(T_0_0)) char storage[sizeof(T_0_0)];
155+
// CHECK-NEXT: auto * _Nonnull storageObjectPtr = reinterpret_cast<T_0_0 *>(storage);
156+
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(storage, swift::_impl::getOpaquePointer(x), swift::TypeMetadataTrait<T_0_0>::getTypeMetadata());
157+
// CHECK-NEXT: T_0_0 result(std::move(*storageObjectPtr));
158+
// CHECK-NEXT: storageObjectPtr->~T_0_0();
159+
// CHECK-NEXT: return result;
153160
// CHECK-NEXT: } else {
154161
// CHECK-NEXT: T_0_0 returnValue;
155162
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast<void *>(&returnValue), swift::_impl::getOpaquePointer(x), swift::TypeMetadataTrait<T_0_0>::getTypeMetadata());
@@ -174,6 +181,13 @@ public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct {
174181
// CHECK-NEXT: return ::swift::_impl::implClassFor<T_0_0>::type::returnNewValue([&](void * _Nonnull returnValue) {
175182
// CHECK-NEXT: _impl::$s9Functions15TestSmallStructV24genericMethodPassThroughyxxlF(returnValue, swift::_impl::getOpaquePointer(x), _impl::swift_interop_passDirect_Functions_uint32_t_0_4(_getOpaquePointer()), swift::TypeMetadataTrait<T_0_0>::getTypeMetadata());
176183
// CHECK-NEXT: });
184+
// CHECK-NEXT: } else if constexpr (::swift::_impl::isSwiftBridgedCxxRecord<T_0_0>) {
185+
// CHECK-NEXT: alignas(alignof(T_0_0)) char storage[sizeof(T_0_0)];
186+
// CHECK-NEXT: auto * _Nonnull storageObjectPtr = reinterpret_cast<T_0_0 *>(storage);
187+
// CHECK-NEXT: _impl::$s9Functions15TestSmallStructV24genericMethodPassThroughyxxlF(storage, swift::_impl::getOpaquePointer(x), _impl::swift_interop_passDirect_Functions_uint32_t_0_4(_getOpaquePointer()), swift::TypeMetadataTrait<T_0_0>::getTypeMetadata())
188+
// CHECK-NEXT: T_0_0 result(std::move(*storageObjectPtr));
189+
// CHECK-NEXT: storageObjectPtr->~T_0_0();
190+
// CHECK-NEXT: return result;
177191
// CHECK-NEXT: } else {
178192
// CHECK-NEXT: T_0_0 returnValue;
179193
// CHECK-NEXT: _impl::$s9Functions15TestSmallStructV24genericMethodPassThroughyxxlF(reinterpret_cast<void *>(&returnValue), swift::_impl::getOpaquePointer(x), _impl::swift_interop_passDirect_Functions_uint32_t_0_4(_getOpaquePointer()), swift::TypeMetadataTrait<T_0_0>::getTypeMetadata());

test/Interop/SwiftToCxx/generics/generic-struct-in-cxx.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,8 @@ public func inoutConcretePair(_ x: UInt16, _ y: inout GenericPair<UInt16, UInt16
304304
// CHECK-NEXT: return ::swift::_impl::implClassFor<T_0_1>::type::returnNewValue([&](void * _Nonnull returnValue) {
305305
// CHECK-NEXT: _impl::$s8Generics11GenericPairV1yq_vg(returnValue, swift::TypeMetadataTrait<GenericPair<T_0_0, T_0_1>>::getTypeMetadata(), _getOpaquePointer());
306306
// CHECK-NEXT: });
307-
// CHECK-NEXT: } else {
307+
// CHECK-NEXT: } else if constexpr (::swift::_impl::isSwiftBridgedCxxRecord<T_0_1>) {
308+
// CHECK: } else {
308309
// CHECK-NEXT: T_0_1 returnValue;
309310
// CHECK-NEXT: _impl::$s8Generics11GenericPairV1yq_vg(reinterpret_cast<void *>(&returnValue), swift::TypeMetadataTrait<GenericPair<T_0_0, T_0_1>>::getTypeMetadata(), _getOpaquePointer());
310311
// CHECK-NEXT: return returnValue;
@@ -345,7 +346,8 @@ public func inoutConcretePair(_ x: UInt16, _ y: inout GenericPair<UInt16, UInt16
345346
// CHECK-NEXT: return ::swift::_impl::implClassFor<T_1_0>::type::returnNewValue([&](void * _Nonnull returnValue) {
346347
// CHECK-NEXT: _impl::$s8Generics11GenericPairV13genericMethodyqd__qd___q_tlF(returnValue, swift::_impl::getOpaquePointer(x), swift::_impl::getOpaquePointer(y), swift::TypeMetadataTrait<GenericPair<T_0_0, T_0_1>>::getTypeMetadata(), swift::TypeMetadataTrait<T_1_0>::getTypeMetadata(), _getOpaquePointer());
347348
// CHECK-NEXT: });
348-
// CHECK-NEXT: } else {
349+
// CHECK-NEXT: } else if constexpr (::swift::_impl::isSwiftBridgedCxxRecord<T_1_0>) {
350+
// CHECK: } else {
349351
// CHECK-NEXT: T_1_0 returnValue;
350352
// CHECK-NEXT: _impl::$s8Generics11GenericPairV13genericMethodyqd__qd___q_tlF(reinterpret_cast<void *>(&returnValue), swift::_impl::getOpaquePointer(x), swift::_impl::getOpaquePointer(y), swift::TypeMetadataTrait<GenericPair<T_0_0, T_0_1>>::getTypeMetadata(), swift::TypeMetadataTrait<T_1_0>::getTypeMetadata(), _getOpaquePointer());
351353
// CHECK-NEXT: return returnValue;

0 commit comments

Comments
 (0)