Skip to content

Commit 0b718b6

Browse files
committed
[PrintAsClang] Fix thunks for throwing Never funcs
Extend the previous commit’s support for functions that return Never to also properly generate code for *throwing* Never functions. This is a little subtle because: • At the SWIFT_CALL level, throwing Never functions are *not* noreturn • At the thunk level, throwing Never functions are noreturn *only* if you’re using exceptions; if you’re using swift::Expected, they should throw • In either case, the compiler cannot statically prove that thunks are noreturn except on the error path, so we need to add an abort() call on the success path
1 parent 4d63f9a commit 0b718b6

File tree

7 files changed

+54
-5
lines changed

7 files changed

+54
-5
lines changed

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,7 +1410,10 @@ class DeclAndTypePrinter::Implementation
14101410
/// Print C or C++ trailing attributes for a function declaration.
14111411
void printFunctionClangAttributes(FuncDecl *FD, AnyFunctionType *funcTy) {
14121412
if (funcTy->getResult()->isUninhabited()) {
1413-
os << " SWIFT_NORETURN";
1413+
if (funcTy->isThrowing())
1414+
os << " SWIFT_NORETURN_EXCEPT_ERRORS";
1415+
else
1416+
os << " SWIFT_NORETURN";
14141417
} else if (!funcTy->getResult()->isVoid() &&
14151418
!FD->getAttrs().hasAttribute<DiscardableResultAttr>()) {
14161419
os << " SWIFT_WARN_UNUSED_RESULT";
@@ -1489,12 +1492,15 @@ class DeclAndTypePrinter::Implementation
14891492
// Swift functions can't throw exceptions, we can only
14901493
// throw them from C++ when emitting C++ inline thunks for the Swift
14911494
// functions.
1492-
if (!funcTy->isThrowing())
1495+
if (!funcTy->isThrowing()) {
14931496
os << " SWIFT_NOEXCEPT";
1497+
// Lowered Never-returning functions *are* considered to return when they
1498+
// throw, so only use SWIFT_NORETURN on non-throwing functions.
1499+
if (funcTy->getResult()->isUninhabited())
1500+
os << " SWIFT_NORETURN";
1501+
}
14941502
if (!funcABI.useCCallingConvention())
14951503
os << " SWIFT_CALL";
1496-
if (funcTy->getResult()->isUninhabited())
1497-
os << " SWIFT_NORETURN";
14981504
printAvailability(FD);
14991505
os << ';';
15001506
if (funcABI.useMangledSymbolName()) {

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
14441444
if (resultTy->isVoid()) {
14451445
os << " return swift::Expected<void>(swift::Error(opaqueError));\n";
14461446
os << "#endif\n";
1447+
if (FD->getInterfaceType()->castTo<FunctionType>()->getResult()->isUninhabited())
1448+
os << " abort();\n";
14471449
} else {
14481450
auto directResultType = signature.getDirectResultType();
14491451
printDirectReturnOrParamCType(

lib/PrintAsClang/_SwiftStdlibCxxOverlay.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,12 +413,14 @@ template<class T>
413413
using ThrowingResult = T;
414414

415415
#define SWIFT_RETURN_THUNK(T, v) v
416+
#define SWIFT_NORETURN_EXCEPT_ERRORS SWIFT_NORETURN
416417

417418
#else
418419

419420
template <class T> using ThrowingResult = swift::Expected<T>;
420421

421422
#define SWIFT_RETURN_THUNK(T, v) swift::Expected<T>(v)
423+
#define SWIFT_NORETURN_EXCEPT_ERRORS
422424

423425
#endif
424426

test/Interop/SwiftToCxx/functions/swift-expected-execution.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ int main() {
8989
valueError.getMessage();
9090
}
9191

92+
auto expectedResult2 = Functions::throwFunctionWithNeverReturn();
93+
if (!expectedResult2.has_value()) {
94+
auto error = expectedResult2.error();
95+
auto optionalError = error.as<Functions::NaiveErrors>();
96+
assert(optionalError.isSome());
97+
auto valueError = optionalError.get();
98+
assert(valueError == Functions::NaiveErrors::returnError);
99+
valueError.getMessage();
100+
}
101+
92102
// Test get T's Value (const)
93103
const auto valueExp = testIntValue;
94104
if (valueExp.value() == 42)
@@ -116,6 +126,8 @@ int main() {
116126
// CHECK-NEXT: returnError
117127
// CHECK-NEXT: passThrowFunctionWithPossibleReturn
118128
// CHECK-NEXT: returnError
129+
// CHECK-NEXT: passThrowFunctionWithNeverReturn
130+
// CHECK-NEXT: returnError
119131
// CHECK-NEXT: Test get T's Value (const)
120132
// CHECK-NEXT: Test get T's Value
121133
// CHECK-NEXT: testIntValue has a value

test/Interop/SwiftToCxx/functions/swift-functions-errors-execution.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ int main() {
4646
} catch (swift::Error& e) {
4747
printf("Exception\n");
4848
}
49+
try {
50+
Functions::throwFunctionWithNeverReturn();
51+
} catch (swift::Error& e) {
52+
printf("Exception\n");
53+
}
4954
try {
5055
Functions::testDestroyedError();
5156
} catch(const swift::Error &e) { }
@@ -58,4 +63,6 @@ int main() {
5863
// CHECK-NEXT: throwError
5964
// CHECK-NEXT: passThrowFunctionWithReturn
6065
// CHECK-NEXT: Exception
66+
// CHECK-NEXT: passThrowFunctionWithNeverReturn
67+
// CHECK-NEXT: Exception
6168
// CHECK-NEXT: Test destroyed

test/Interop/SwiftToCxx/functions/swift-functions-errors.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
// CHECK: SWIFT_EXTERN void $s9Functions18emptyThrowFunctionyyKF(SWIFT_CONTEXT void * _Nonnull _ctx, SWIFT_ERROR_RESULT void * _Nullable * _Nullable _error) SWIFT_CALL; // emptyThrowFunction()
1515
// CHECK: SWIFT_EXTERN void $s9Functions18testDestroyedErroryyKF(SWIFT_CONTEXT void * _Nonnull _ctx, SWIFT_ERROR_RESULT void * _Nullable * _Nullable _error) SWIFT_CALL; // testDestroyedError()
1616
// CHECK: SWIFT_EXTERN void $s9Functions13throwFunctionyyKF(SWIFT_CONTEXT void * _Nonnull _ctx, SWIFT_ERROR_RESULT void * _Nullable * _Nullable _error) SWIFT_CALL; // throwFunction()
17+
// CHECK: SWIFT_EXTERN void $s9Functions28throwFunctionWithNeverReturns0E0OyKF(SWIFT_CONTEXT void * _Nonnull _ctx, SWIFT_ERROR_RESULT void * _Nullable * _Nullable _error) SWIFT_CALL; // throwFunctionWithNeverReturn()
1718
// CHECK: SWIFT_EXTERN ptrdiff_t $s9Functions31throwFunctionWithPossibleReturnyS2iKF(ptrdiff_t a, SWIFT_CONTEXT void * _Nonnull _ctx, SWIFT_ERROR_RESULT void * _Nullable * _Nullable _error) SWIFT_CALL; // throwFunctionWithPossibleReturn(_:)
1819
// CHECK: SWIFT_EXTERN ptrdiff_t $s9Functions23throwFunctionWithReturnSiyKF(SWIFT_CONTEXT void * _Nonnull _ctx, SWIFT_ERROR_RESULT void * _Nullable * _Nullable _error) SWIFT_CALL; // throwFunctionWithReturn()
1920

@@ -89,6 +90,25 @@ public func throwFunction() throws {
8990
// CHECK: #endif
9091
// CHECK: }
9192

93+
@_expose(Cxx)
94+
public func throwFunctionWithNeverReturn() throws -> Never {
95+
print("passThrowFunctionWithNeverReturn")
96+
throw NaiveErrors.returnError
97+
}
98+
99+
// CHECK: SWIFT_INLINE_THUNK swift::ThrowingResult<void> throwFunctionWithNeverReturn() SWIFT_SYMBOL("s:9Functions28throwFunctionWithNeverReturns0E0OyKF") SWIFT_NORETURN_EXCEPT_ERRORS {
100+
// CHECK-NEXT: void* opaqueError = nullptr;
101+
// CHECK-NEXT: void* _ctx = nullptr;
102+
// CHECK-NEXT: _impl::$s9Functions28throwFunctionWithNeverReturns0E0OyKF(_ctx, &opaqueError);
103+
// CHECK-NEXT: if (opaqueError != nullptr)
104+
// CHECK-NEXT: #ifdef __cpp_exceptions
105+
// CHECK-NEXT: throw (swift::Error(opaqueError));
106+
// CHECK-NEXT: #else
107+
// CHECK-NEXT: return swift::Expected<void>(swift::Error(opaqueError));
108+
// CHECK-NEXT: #endif
109+
// CHECK-NEXT: abort();
110+
// CHECK-NEXT: }
111+
92112
@_expose(Cxx)
93113
public func throwFunctionWithPossibleReturn(_ a: Int) throws -> Int {
94114
print("passThrowFunctionWithPossibleReturn")

test/Interop/SwiftToCxx/functions/swift-functions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// CHECK: SWIFT_EXTERN int $s9Functions016passTwoIntReturnD01x1ys5Int32VAF_AFtF(int x, int y) SWIFT_NOEXCEPT SWIFT_CALL; // passTwoIntReturnInt(x:y:)
1313
// CHECK: SWIFT_EXTERN int $s9Functions016passTwoIntReturnD10NoArgLabelys5Int32VAD_ADtF(int, int) SWIFT_NOEXCEPT SWIFT_CALL; // passTwoIntReturnIntNoArgLabel(_:_:)
1414
// CHECK: SWIFT_EXTERN int $s9Functions016passTwoIntReturnD19NoArgLabelParamNameys5Int32VAD_ADtF(int x2, int y2) SWIFT_NOEXCEPT SWIFT_CALL; // passTwoIntReturnIntNoArgLabelParamName(_:_:)
15-
// CHECK: SWIFT_EXTERN void $s9Functions19passVoidReturnNevers0E0OyF(void) SWIFT_NOEXCEPT SWIFT_CALL SWIFT_NORETURN; // passVoidReturnNever()
15+
// CHECK: SWIFT_EXTERN void $s9Functions19passVoidReturnNevers0E0OyF(void) SWIFT_NOEXCEPT SWIFT_NORETURN SWIFT_CALL; // passVoidReturnNever()
1616
// CHECK: SWIFT_EXTERN void $s9Functions014passVoidReturnC0yyF(void) SWIFT_NOEXCEPT SWIFT_CALL; // passVoidReturnVoid()
1717

1818
// CHECK: }

0 commit comments

Comments
 (0)