Skip to content

Commit af32bbf

Browse files
committed
[interop][SwiftToCxx] generics: add support for returning primitive generic types
1 parent ea9276f commit af32bbf

File tree

3 files changed

+42
-2
lines changed

3 files changed

+42
-2
lines changed

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ bool isResilientType(Type t) {
6666
return false;
6767
}
6868

69+
bool isGenericType(Type t) { return t->is<GenericTypeParamType>(); }
70+
6971
bool isKnownCxxType(Type t, PrimitiveTypeMapping &typeMapping) {
7072
return isKnownType(t, typeMapping, OutputLanguageMode::Cxx);
7173
}
@@ -223,7 +225,12 @@ class CFunctionSignatureTypePrinter
223225
Optional<OptionalTypeKind> optionalKind,
224226
bool isInOutParam) {
225227
// FIXME: handle optionalKind.
226-
// FIXME: handle isInOutParam.
228+
if (typeUseKind == FunctionSignatureTypeUse::ReturnType) {
229+
// generic is always returned indirectly in C signature.
230+
assert(languageMode == OutputLanguageMode::Cxx);
231+
os << genericTpt->getName();
232+
return;
233+
}
227234
if (!isInOutParam)
228235
os << "const ";
229236
if (languageMode == OutputLanguageMode::Cxx) {
@@ -321,7 +328,7 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
321328
bool isIndirectReturnType =
322329
kind == FunctionSignatureKind::CFunctionProto &&
323330
!isKnownCType(resultTy, typeMapping) &&
324-
(isResilientType(resultTy) ||
331+
(isResilientType(resultTy) || isGenericType(resultTy) ||
325332
interopContext.getIrABIDetails().shouldReturnIndirectly(resultTy));
326333
if (!isIndirectReturnType) {
327334
OptionalTypeKind retKind;
@@ -542,6 +549,16 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
542549
// indirectly by a pointer.
543550
if (!isKnownCxxType(resultTy, typeMapping) &&
544551
!hasKnownOptionalNullableCxxMapping(resultTy)) {
552+
if (isGenericType(resultTy)) {
553+
// FIXME: Support returning value types.
554+
os << " T returnValue;\n";
555+
std::string returnAddress;
556+
llvm::raw_string_ostream ros(returnAddress);
557+
ros << "reinterpret_cast<void *>(&returnValue)";
558+
printCallToCFunc(/*additionalParam=*/StringRef(ros.str()));
559+
os << ";\n return returnValue;\n";
560+
return;
561+
}
545562
if (auto *decl = resultTy->getNominalOrBoundGenericNominal()) {
546563
if ((isa<StructDecl>(decl) || isa<EnumDecl>(decl))) {
547564
bool isIndirect =

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,5 +116,15 @@ int main() {
116116
assert(x == -13);
117117
assert(y == 42);
118118
}
119+
120+
{
121+
int x = 4;
122+
assert(genericRet(x) == 4);
123+
}
124+
125+
{
126+
double x = -19.75;
127+
assert(genericRet(x) == -19.75);
128+
}
119129
return 0;
120130
}

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,14 @@ public func genericSwap<T>(_ x: inout T, _ y: inout T) {
2727
y = t
2828
}
2929

30+
public func genericRet<T>(_ x: T) -> T {
31+
return x
32+
}
33+
3034
// CHECK: SWIFT_EXTERN void $s9Functions20genericPrintFunctionyyxlF(const void * _Nonnull x, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunction(_:)
3135
// CHECK-NEXT: SWIFT_EXTERN void $s9Functions32genericPrintFunctionMultiGenericyySi_xxSiq_tr0_lF(ptrdiff_t x, const void * _Nonnull t1, const void * _Nonnull t1p, ptrdiff_t y, const void * _Nonnull t2, void * _Nonnull , void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunctionMultiGeneric(_:_:_:_:_:)
3236
// CHECK-NEXT: SWIFT_EXTERN void $s9Functions26genericPrintFunctionTwoArgyyx_SitlF(const void * _Nonnull x, ptrdiff_t y, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunctionTwoArg(_:_:)
37+
// CHECK-NEXT: SWIFT_EXTERN void $s9Functions10genericRetyxxlF(SWIFT_INDIRECT_RESULT void * _Nonnull, const void * _Nonnull x, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericRet(_:)
3338
// CHECK-NEXT: SWIFT_EXTERN void $s9Functions11genericSwapyyxz_xztlF(void * _Nonnull x, void * _Nonnull y, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericSwap(_:_:)
3439

3540
// CHECK: template<class T>
@@ -52,6 +57,14 @@ public func genericSwap<T>(_ x: inout T, _ y: inout T) {
5257
// CHECK-NEXT: return _impl::$s9Functions26genericPrintFunctionTwoArgyyx_SitlF(reinterpret_cast<const void *>(&x), y, swift::getTypeMetadata<T>());
5358
// CHECK-NEXT: }
5459

60+
// CHECK: template<class T>
61+
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
62+
// CHECK-NEXT: inline T genericRet(const T & x) noexcept SWIFT_WARN_UNUSED_RESULT {
63+
// CHECK-NEXT: T returnValue;
64+
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast<void *>(&returnValue), reinterpret_cast<const void *>(&x), swift::getTypeMetadata<T>());
65+
// CHECK-NEXT: return returnValue;
66+
// CHECK-NEXT: }
67+
5568
// CHECK: template<class T>
5669
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
5770
// CHECK-NEXT: inline void genericSwap(T & x, T & y) noexcept {

0 commit comments

Comments
 (0)