Skip to content

Commit 330fc0b

Browse files
committed
[interop][SwiftToCxx] generic functions should return value types correctly
1 parent bf224c7 commit 330fc0b

File tree

7 files changed

+68
-16
lines changed

7 files changed

+68
-16
lines changed

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,10 +576,10 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
576576
if (!isKnownCxxType(resultTy, typeMapping) &&
577577
!hasKnownOptionalNullableCxxMapping(resultTy)) {
578578
if (isGenericType(resultTy)) {
579-
// FIXME: Support returning value types.
580579
std::string returnAddress;
581580
llvm::raw_string_ostream ros(returnAddress);
582581
ros << "reinterpret_cast<void *>(&returnValue)";
582+
StringRef resultTyName = "T"; // FIXME
583583

584584
os << " if constexpr (std::is_base_of<::swift::"
585585
<< cxx_synthesis::getCxxImplNamespaceName()
@@ -589,6 +589,14 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
589589
os << ";\n";
590590
os << " return ::swift::" << cxx_synthesis::getCxxImplNamespaceName()
591591
<< "::implClassFor<T>::type::makeRetained(returnValue);\n";
592+
os << " } else if constexpr (::swift::"
593+
<< cxx_synthesis::getCxxImplNamespaceName() << "::isValueType<"
594+
<< resultTyName << ">) {\n";
595+
os << " return ::swift::" << cxx_synthesis::getCxxImplNamespaceName()
596+
<< "::implClassFor<" << resultTyName
597+
<< ">::type::returnNewValue([&](void * _Nonnull returnValue) {\n";
598+
printCallToCFunc(/*additionalParam=*/StringRef("returnValue"));
599+
os << ";\n });\n";
592600
os << " } else {\n";
593601
os << " T returnValue;\n";
594602
printCallToCFunc(/*additionalParam=*/StringRef(ros.str()));

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -475,8 +475,6 @@ void ClangValueTypePrinter::printTypeGenericTraits(
475475
os << "::";
476476
printer.printBaseName(typeDecl);
477477
os << "> = true;\n";
478-
os << "#pragma clang diagnostic pop\n";
479-
480478
os << "template<>\n";
481479
os << "inline void * _Nonnull getTypeMetadata<";
482480
printer.printBaseName(typeDecl->getModuleContext());
@@ -488,8 +486,18 @@ void ClangValueTypePrinter::printTypeGenericTraits(
488486
os << "::" << cxx_synthesis::getCxxImplNamespaceName()
489487
<< "::" << typeMetadataFuncName << "(0)._0;\n";
490488
os << "}\n";
491-
if (isa<ClassDecl>(typeDecl)) {
489+
492490
os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << "{\n";
491+
492+
if (!isa<ClassDecl>(typeDecl)) {
493+
os << "template<>\n";
494+
os << "static inline const constexpr bool isValueType<";
495+
printer.printBaseName(typeDecl->getModuleContext());
496+
os << "::";
497+
printer.printBaseName(typeDecl);
498+
os << "> = true;\n";
499+
}
500+
493501
os << "template<>\n";
494502
os << "struct implClassFor<";
495503
printer.printBaseName(typeDecl->getModuleContext());
@@ -501,9 +509,9 @@ void ClangValueTypePrinter::printTypeGenericTraits(
501509
printCxxImplClassName(os, typeDecl);
502510
os << "; };\n";
503511
os << "} // namespace\n";
504-
}
505-
os << "} // namespace swift\n";
506-
os << "\nnamespace ";
507-
printer.printBaseName(typeDecl->getModuleContext());
508-
os << " {\n";
512+
os << "#pragma clang diagnostic pop\n";
513+
os << "} // namespace swift\n";
514+
os << "\nnamespace ";
515+
printer.printBaseName(typeDecl->getModuleContext());
516+
os << " {\n";
509517
}

stdlib/public/SwiftShims/_SwiftCxxInteroperability.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,6 @@ using UInt = size_t;
104104
template <class T>
105105
static inline const constexpr bool isUsableInGenericContext = false;
106106

107-
#pragma clang diagnostic pop
108-
109107
/// Returns the type metadat for the given Swift type T.
110108
template <class T> inline void *_Nonnull getTypeMetadata();
111109

@@ -117,8 +115,13 @@ template <class T> struct implClassFor {
117115
// using type = ...;
118116
};
119117

118+
/// True if the given type is a Swift value type.
119+
template <class T> static inline const constexpr bool isValueType = false;
120+
120121
} // namespace _impl
121122

123+
#pragma clang diagnostic pop
124+
122125
} // namespace swift
123126
#endif
124127

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ public final class ClassWithIntField {
6565
// CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions"
6666
// CHECK-NEXT: template<>
6767
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<Class::ClassWithIntField> = true;
68-
// CHECK-NEXT: #pragma clang diagnostic pop
6968
// CHECK-NEXT: template<>
7069
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<Class::ClassWithIntField>() {
7170
// CHECK-NEXT: return Class::_impl::$s5Class0A12WithIntFieldCMa(0)._0;
@@ -74,6 +73,7 @@ public final class ClassWithIntField {
7473
// CHECK-NEXT: template<>
7574
// CHECK-NEXT: struct implClassFor<Class::ClassWithIntField> { using type = Class::_impl::_impl_ClassWithIntField; };
7675
// CHECK-NEXT: } // namespace
76+
// CHECK-NEXT: #pragma clang diagnostic pop
7777
// CHECK-NEXT: } // namespace swift
7878
// CHECK-EMPTY:
7979
// CHECK-NEXT: namespace Class {

test/Interop/SwiftToCxx/generics/generic-function-execution.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,19 @@ int main() {
171171
genericSwap(x, y);
172172
genericPrintFunction(x);
173173
genericPrintFunction(y);
174+
auto xy = genericRet(x);
175+
genericPrintFunction(xy);
176+
xy.mut();
177+
genericPrintFunction(xy);
178+
genericPrintFunction(x);
174179
}
175180
// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 11, x2: 12, x3: 10, x4: 11, x5: 13, x6: 9)
176181
// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: -9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -11)
177182
// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: -9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -11)
178-
// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 11, x2: 12, x3: 10, x4: 11, x5: 13, x6: 9)
183+
// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 11, x2: 12, x3: 10, x4: 11, x5: 13, x6: 9)
184+
// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: -9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -11)
185+
// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -7)
186+
// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: -9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -11)
179187

180188
{
181189
auto x = createTestSmallStruct(45);
@@ -185,12 +193,18 @@ int main() {
185193
genericSwap(y, x);
186194
genericPrintFunction(x);
187195
genericPrintFunction(y);
196+
auto xy = genericRet(x);
197+
genericPrintFunction(xy);
198+
xy.mut();
199+
genericPrintFunction(xy);
200+
genericPrintFunction(x);
188201
}
189202
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 45)
190203
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233)
191204
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233)
192205
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 45)
193-
194-
// FIXME: return struct.
206+
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233)
207+
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 4294902062)
208+
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233)
195209
return 0;
196210
}

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ public struct TestLargeStruct {
5151
x5 = x+2
5252
x6 = x-2
5353
}
54+
55+
public mutating func mut() {
56+
x1 = -x1
57+
x6 = x5
58+
}
5459
}
5560

5661
public func createTestLargeStruct(_ x: Int) -> TestLargeStruct {
@@ -59,6 +64,10 @@ public func createTestLargeStruct(_ x: Int) -> TestLargeStruct {
5964

6065
public struct TestSmallStruct {
6166
var x1: UInt32
67+
68+
public mutating func mut() {
69+
x1 = ~x1
70+
}
6271
}
6372

6473
public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct {
@@ -102,6 +111,10 @@ public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct {
102111
// CHECK-NEXT: void *returnValue;
103112
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast<void *>(&returnValue), reinterpret_cast<const void *>(&x), swift::getTypeMetadata<T>());
104113
// CHECK-NEXT: return ::swift::_impl::implClassFor<T>::type::makeRetained(returnValue);
114+
// CHECK-NEXT: } else if constexpr (::swift::_impl::isValueType<T>) {
115+
// CHECK-NEXT: return ::swift::_impl::implClassFor<T>::type::returnNewValue([&](void * _Nonnull returnValue) {
116+
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(returnValue, reinterpret_cast<const void *>(&x), swift::getTypeMetadata<T>());
117+
// CHECK-NEXT: });
105118
// CHECK-NEXT: } else {
106119
// CHECK-NEXT: T returnValue;
107120
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast<void *>(&returnValue), reinterpret_cast<const void *>(&x), swift::getTypeMetadata<T>());

test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,17 @@
6969
// CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions"
7070
// CHECK-NEXT: template<>
7171
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<Structs::StructWithIntField> = true;
72-
// CHECK-NEXT: #pragma clang diagnostic pop
7372
// CHECK-NEXT: template<>
7473
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<Structs::StructWithIntField>() {
7574
// CHECK-NEXT: return Structs::_impl::$s7Structs18StructWithIntFieldVMa(0)._0;
7675
// CHECK-NEXT: }
76+
// CHECK-NEXT: namespace _impl{
77+
// CHECK-NEXT: template<>
78+
// CHECK-NEXT: static inline const constexpr bool isValueType<Structs::StructWithIntField> = true;
79+
// CHECK-NEXT: template<>
80+
// CHECK-NEXT: struct implClassFor<Structs::StructWithIntField> { using type = Structs::_impl::_impl_StructWithIntField; };
81+
// CHECK-NEXT: } // namespace
82+
// CHECK-NEXT: #pragma clang diagnostic pop
7783
// CHECK-NEXT: } // namespace swift
7884
// CHECK-EMPTY:
7985
// CHECK-NEXT: namespace Structs {

0 commit comments

Comments
 (0)