Skip to content

Commit ce666ac

Browse files
[Interop][SwiftToCxx] Adding support to return Swift::Expected when exceptions are not available.
1 parent a2633d9 commit ce666ac

File tree

4 files changed

+135
-13
lines changed

4 files changed

+135
-13
lines changed

Diff for: lib/PrintAsClang/PrintClangFunction.cpp

+41-2
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,8 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature(
688688
ClangRepresentation::representable;
689689

690690
// Print out the return type.
691+
if (FD->hasThrows() && outputLang == OutputLanguageMode::Cxx)
692+
os << "Swift::ThrowingResult<";
691693
if (kind == FunctionSignatureKind::CFunctionProto) {
692694
// First, verify that the C++ return type is representable.
693695
{
@@ -740,7 +742,8 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature(
740742
.isUnsupported())
741743
return resultingRepresentation;
742744
}
743-
745+
if (FD->hasThrows() && outputLang == OutputLanguageMode::Cxx)
746+
os << ">";
744747
os << ' ';
745748
if (const auto *typeDecl = modifiers.qualifierContext)
746749
ClangSyntaxPrinter(os).printNominalTypeQualifier(
@@ -1241,13 +1244,49 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
12411244
// Create the condition and the statement to throw an exception.
12421245
if (hasThrows) {
12431246
os << " if (opaqueError != nullptr)\n";
1247+
os << "#ifdef __cpp_exceptions\n";
12441248
os << " throw (Swift::Error(opaqueError));\n";
1249+
os << "#else\n";
1250+
if (resultTy->isVoid()) {
1251+
os << " return SWIFT_RETURN_THUNK(void, Swift::Error(opaqueError));\n";
1252+
} else {
1253+
os << " return SWIFT_RETURN_THUNK(";
1254+
auto directResultType = signature.getDirectResultType();
1255+
printDirectReturnOrParamCType(
1256+
*directResultType, resultTy, moduleContext, os, cPrologueOS,
1257+
typeMapping, interopContext, [&]() {
1258+
OptionalTypeKind retKind;
1259+
Type objTy;
1260+
std::tie(objTy, retKind) =
1261+
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);
1262+
1263+
auto s = printClangFunctionReturnType(objTy, retKind, const_cast<ModuleDecl *>(moduleContext),
1264+
OutputLanguageMode::Cxx);
1265+
assert(!s.isUnsupported());
1266+
});
1267+
os << ", Swift::Error(opaqueError));\n";
1268+
}
1269+
os << "#endif\n";
12451270
}
12461271

12471272
// Return the function result value if it doesn't throw.
12481273
if (!resultTy->isVoid() && hasThrows) {
12491274
os << "\n";
1250-
os << "return returnValue;\n";
1275+
os << " return SWIFT_RETURN_THUNK(";
1276+
auto directResultType = signature.getDirectResultType();
1277+
printDirectReturnOrParamCType(
1278+
*directResultType, resultTy, moduleContext, os, cPrologueOS,
1279+
typeMapping, interopContext, [&]() {
1280+
OptionalTypeKind retKind;
1281+
Type objTy;
1282+
std::tie(objTy, retKind) =
1283+
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);
1284+
1285+
auto s = printClangFunctionReturnType(objTy, retKind, const_cast<ModuleDecl *>(moduleContext),
1286+
OutputLanguageMode::Cxx);
1287+
assert(!s.isUnsupported());
1288+
});
1289+
os << ", returnValue);\n";
12511290
}
12521291
}
12531292

Diff for: lib/PrintAsClang/_SwiftStdlibCxxOverlay.h

+17
Original file line numberDiff line numberDiff line change
@@ -352,4 +352,21 @@ class Expected<void> {
352352
alignas(alignof(Swift::Error)) char buffer[sizeof(Swift::Error)];
353353
bool has_val;
354354
};
355+
356+
#ifdef __cpp_exceptions
357+
358+
template<class T>
359+
using ThrowingResult = T;
360+
361+
#define SWIFT_RETURN_THUNK(T, v) v
362+
363+
#else
364+
365+
template<class T>
366+
using ThrowingResult = Swift::Expected<T>;
367+
368+
#define SWIFT_RETURN_THUNK(T, v) Swift::Expected<T>(v)
369+
370+
#endif
371+
355372
#endif

Diff for: test/Interop/SwiftToCxx/functions/swift-expected-execution.cpp

+26-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
// RUN: %target-swift-frontend %S/swift-functions-errors.swift -typecheck -module-name Functions -Xcc -fno-exceptions -enable-experimental-cxx-interop -emit-clang-header-path %t/functions.h
44

5-
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-expected-execution.o
5+
// RUN: %target-interop-build-clangxx -c %s -I %t -fno-exceptions -o %t/swift-expected-execution.o
66
// RUN: %target-interop-build-swift %S/swift-functions-errors.swift -o %t/swift-expected-execution -Xlinker %t/swift-expected-execution.o -module-name Functions -Xfrontend -entry-point-function-name -Xfrontend swiftMain
77

88
// RUN: %target-codesign %t/swift-expected-execution
@@ -11,6 +11,7 @@
1111
// REQUIRES: executable_test
1212
// UNSUPPORTED: OS=windows-msvc
1313

14+
#include <cassert>
1415
#include <cstdio>
1516
#include "functions.h"
1617

@@ -64,6 +65,26 @@ int main() {
6465
printf("Test operator bool\n");
6566
}
6667

68+
const auto constExpectedResult = Functions::throwFunctionWithPossibleReturn(0);
69+
if (!constExpectedResult.has_value()) {
70+
auto constError = constExpectedResult.error();
71+
auto optionalError = constError.as<Functions::NaiveErrors>();
72+
assert(optionalError.isSome());
73+
auto valueError = optionalError.get();
74+
assert(valueError == Functions::NaiveErrors::returnError);
75+
valueError.getMessage();
76+
}
77+
78+
auto expectedResult = Functions::throwFunctionWithPossibleReturn(0);
79+
if (!expectedResult.has_value()) {
80+
auto error = expectedResult.error();
81+
auto optionalError = error.as<Functions::NaiveErrors>();
82+
assert(optionalError.isSome());
83+
auto valueError = optionalError.get();
84+
assert(valueError == Functions::NaiveErrors::returnError);
85+
valueError.getMessage();
86+
}
87+
6788
// Test get T's Value (const)
6889
const auto valueExp = testIntValue;
6990
if (valueExp.value() == 42)
@@ -87,6 +108,10 @@ int main() {
87108
// CHECK-NEXT: Test Reference to T's members (const)
88109
// CHECK-NEXT: Test Reference to T's members
89110
// CHECK-NEXT: Test operator bool
111+
// CHECK-NEXT: passThrowFunctionWithPossibleReturn
112+
// CHECK-NEXT: returnError
113+
// CHECK-NEXT: passThrowFunctionWithPossibleReturn
114+
// CHECK-NEXT: returnError
90115
// CHECK-NEXT: Test get T's Value (const)
91116
// CHECK-NEXT: Test get T's Value
92117
// CHECK-NEXT: testIntValue has a value

Diff for: test/Interop/SwiftToCxx/functions/swift-functions-errors.swift

+51-10
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99
// CHECK-LABEL: namespace _impl {
1010

1111
// CHECK: SWIFT_EXTERN void $s9Functions18emptyThrowFunctionyyKF(SWIFT_CONTEXT void * _Nonnull _ctx, SWIFT_ERROR_RESULT void * _Nullable * _Nullable _error) SWIFT_CALL; // emptyThrowFunction()
12+
// CHECK: SWIFT_EXTERN void $s9Functions18testDestroyedErroryyKF(SWIFT_CONTEXT void * _Nonnull _ctx, SWIFT_ERROR_RESULT void * _Nullable * _Nullable _error) SWIFT_CALL; // testDestroyedError()
1213
// CHECK: SWIFT_EXTERN void $s9Functions13throwFunctionyyKF(SWIFT_CONTEXT void * _Nonnull _ctx, SWIFT_ERROR_RESULT void * _Nullable * _Nullable _error) SWIFT_CALL; // throwFunction()
14+
// CHECK: SWIFT_EXTERN ptrdiff_t $s9Functions31throwFunctionWithPossibleReturnyS2iKF(ptrdiff_t a, SWIFT_CONTEXT void * _Nonnull _ctx, SWIFT_ERROR_RESULT void * _Nullable * _Nullable _error) SWIFT_CALL; // throwFunctionWithPossibleReturn(_:)
15+
// CHECK: SWIFT_EXTERN ptrdiff_t $s9Functions23throwFunctionWithReturnSiyKF(SWIFT_CONTEXT void * _Nonnull _ctx, SWIFT_ERROR_RESULT void * _Nullable * _Nullable _error) SWIFT_CALL; // throwFunctionWithReturn()
16+
1317

1418
// CHECK: }
1519

@@ -26,12 +30,16 @@ public enum NaiveErrors : Error {
2630
@_expose(Cxx)
2731
public func emptyThrowFunction() throws { print("passEmptyThrowFunction") }
2832

29-
// CHECK: inline void emptyThrowFunction() {
33+
// CHECK: inline Swift::ThrowingResult<void> emptyThrowFunction() {
3034
// CHECK: void* opaqueError = nullptr;
3135
// CHECK: void* _ctx = nullptr;
3236
// CHECK: _impl::$s9Functions18emptyThrowFunctionyyKF(_ctx, &opaqueError);
3337
// CHECK: if (opaqueError != nullptr)
34-
// CHECK: throw (Swift::Error(opaqueError))
38+
// CHECK: #ifdef __cpp_exceptions
39+
// CHECK: throw (Swift::Error(opaqueError));
40+
// CHECK: #else
41+
// CHECK: return SWIFT_RETURN_THUNK(void, Swift::Error(opaqueError));
42+
// CHECK: #endif
3543
// CHECK: }
3644

3745
class TestDestroyed {
@@ -48,12 +56,16 @@ public struct DestroyedError : Error {
4856
@_expose(Cxx)
4957
public func testDestroyedError() throws { throw DestroyedError() }
5058

51-
// CHECK: inline void testDestroyedError() {
59+
// CHECK: inline Swift::ThrowingResult<void> testDestroyedError() {
5260
// CHECK: void* opaqueError = nullptr;
5361
// CHECK: void* _ctx = nullptr;
5462
// CHECK: _impl::$s9Functions18testDestroyedErroryyKF(_ctx, &opaqueError);
5563
// CHECK: if (opaqueError != nullptr)
56-
// CHECK: throw (Swift::Error(opaqueError))
64+
// CHECK: #ifdef __cpp_exceptions
65+
// CHECK: throw (Swift::Error(opaqueError));
66+
// CHECK: #else
67+
// CHECK: return SWIFT_RETURN_THUNK(void, Swift::Error(opaqueError));
68+
// CHECK: #endif
5769
// CHECK: }
5870

5971
@_expose(Cxx)
@@ -62,12 +74,38 @@ public func throwFunction() throws {
6274
throw NaiveErrors.throwError
6375
}
6476

65-
// CHECK: inline void throwFunction() {
77+
// CHECK: inline Swift::ThrowingResult<void> throwFunction() {
6678
// CHECK: void* opaqueError = nullptr;
6779
// CHECK: void* _ctx = nullptr;
6880
// CHECK: _impl::$s9Functions13throwFunctionyyKF(_ctx, &opaqueError);
6981
// CHECK: if (opaqueError != nullptr)
70-
// CHECK: throw (Swift::Error(opaqueError))
82+
// CHECK: #ifdef __cpp_exceptions
83+
// CHECK: throw (Swift::Error(opaqueError));
84+
// CHECK: #else
85+
// CHECK: return SWIFT_RETURN_THUNK(void, Swift::Error(opaqueError));
86+
// CHECK: #endif
87+
// CHECK: }
88+
89+
@_expose(Cxx)
90+
public func throwFunctionWithPossibleReturn(_ a: Int) throws -> Int {
91+
print("passThrowFunctionWithPossibleReturn")
92+
if (a == 0) {
93+
throw NaiveErrors.returnError
94+
}
95+
return 0
96+
}
97+
98+
// CHECK: inline Swift::ThrowingResult<swift::Int> throwFunctionWithPossibleReturn(swift::Int a) SWIFT_WARN_UNUSED_RESULT {
99+
// CHECK: void* opaqueError = nullptr;
100+
// CHECK: void* _ctx = nullptr;
101+
// CHECK: auto returnValue = _impl::$s9Functions31throwFunctionWithPossibleReturnyS2iKF(a, _ctx, &opaqueError);
102+
// CHECK: if (opaqueError != nullptr)
103+
// CHECK: #ifdef __cpp_exceptions
104+
// CHECK: throw (Swift::Error(opaqueError));
105+
// CHECK: #else
106+
// CHECK: return SWIFT_RETURN_THUNK(swift::Int, Swift::Error(opaqueError));
107+
// CHECK: #endif
108+
// CHECK: return SWIFT_RETURN_THUNK(swift::Int, returnValue);
71109
// CHECK: }
72110

73111
@_expose(Cxx)
@@ -77,11 +115,14 @@ public func throwFunctionWithReturn() throws -> Int {
77115
return 0
78116
}
79117

80-
// CHECK: inline swift::Int throwFunctionWithReturn() SWIFT_WARN_UNUSED_RESULT {
118+
// CHECK: inline Swift::ThrowingResult<swift::Int> throwFunctionWithReturn() SWIFT_WARN_UNUSED_RESULT {
81119
// CHECK: void* opaqueError = nullptr;
82120
// CHECK: void* _ctx = nullptr;
83121
// CHECK: auto returnValue = _impl::$s9Functions23throwFunctionWithReturnSiyKF(_ctx, &opaqueError);
84-
// CHECK: if (opaqueError != nullptr)
85-
// CHECK: throw (Swift::Error(opaqueError))
86-
// CHECK: return returnValue;
122+
// CHECK: #ifdef __cpp_exceptions
123+
// CHECK: throw (Swift::Error(opaqueError));
124+
// CHECK: #else
125+
// CHECK: return SWIFT_RETURN_THUNK(swift::Int, Swift::Error(opaqueError));
126+
// CHECK: #endif
127+
// CHECK: return SWIFT_RETURN_THUNK(swift::Int, returnValue);
87128
// CHECK: }

0 commit comments

Comments
 (0)