Skip to content

Commit 5af07a4

Browse files
test/Interop/SwiftToCxx/functions/swift-functions-errors.swift
1 parent 0f8b42a commit 5af07a4

File tree

3 files changed

+88
-6
lines changed

3 files changed

+88
-6
lines changed

lib/PrintAsClang/_SwiftCxxInteroperability.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,14 @@
2121

2222
#include <cstdint>
2323
#include <stdlib.h>
24+
#include <cstdint>
25+
#include <optional>
2426
#if defined(_WIN32)
2527
#include <malloc.h>
2628
#endif
29+
#if !defined(SWIFT_CALL)
30+
# define SWIFT_CALL __attribute__((swiftcall))
31+
#endif
2732

2833
// FIXME: Use always_inline, artificial.
2934
#define SWIFT_INLINE_THUNK inline
@@ -191,6 +196,47 @@ extern "C" void *_Nonnull swift_errorRetain(void *_Nonnull swiftError) noexcept;
191196

192197
extern "C" void swift_errorRelease(void *_Nonnull swiftError) noexcept;
193198

199+
extern "C" int $ss5ErrorMp; // external global %swift.protocol, align 4
200+
201+
extern "C" int *_Nonnull got_ss5ErrorMp = &$ss5ErrorMp;
202+
203+
extern "C"
204+
const void * _Nullable
205+
swift_getTypeByMangledNameInContext(
206+
const char *_Nullable typeNameStart,
207+
size_t typeNameLength,
208+
const void *_Nullable context,
209+
const void *_Nullable const *_Nullable genericArgs) SWIFT_CALL;
210+
211+
extern "C" bool swift_dynamicCast(void *_Nullable dest, void *_Nullable src,
212+
const void *_Nullable srcType,
213+
const void * _Nullable targetType,
214+
uint32_t flags);
215+
216+
struct SymbolicP {
217+
alignas(2) uint8_t _1;
218+
uint32_t _2;
219+
uint8_t _3[2];
220+
uint8_t _4;
221+
} __attribute__((packed));
222+
223+
inline const void *_Nullable testErrorCall() {
224+
static swift::SymbolicP errorSymbol;
225+
errorSymbol._1 = 2;
226+
errorSymbol._2 = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&got_ss5ErrorMp) - reinterpret_cast<uintptr_t>(&errorSymbol._2));
227+
errorSymbol._3[0] = '_';
228+
errorSymbol._3[1] = 'p';
229+
errorSymbol._4 = 0;
230+
static_assert(sizeof(errorSymbol) == 8, "");
231+
auto charErrorSymbol = reinterpret_cast<const char *>(&errorSymbol);
232+
233+
const void *ptr2 =
234+
swift::swift_getTypeByMangledNameInContext(charErrorSymbol,
235+
sizeof(errorSymbol) - 1,
236+
nullptr, nullptr);
237+
return ptr2;
238+
}
239+
194240
class Error {
195241
public:
196242
Error() {}
@@ -209,6 +255,26 @@ class Error {
209255
opaqueValue = other.opaqueValue;
210256
}
211257

258+
template<class T, class U>
259+
std::optional<T> as() {
260+
char *ptr = (char*)malloc(100);
261+
const void *em = testErrorCall();
262+
void *ep = getPointerToOpaquePointer();
263+
auto metadata = swift::TypeMetadataTrait<T>::getTypeMetadata();
264+
265+
// Dynamic cast will release the error, so we need to retain it.
266+
swift::swift_errorRetain(ep);
267+
bool dynamicCast = swift::swift_dynamicCast(ptr, &ep, em, metadata,/*take on success destroy on failure*/ 6);
268+
269+
if (dynamicCast) {
270+
//swift::_impl::implClassFor<T>::initializeWithTake
271+
auto result =
272+
U::returnNewValue([&](char *dest) { U::initializeWithTake(dest, ptr); });
273+
return std::optional(result);
274+
}
275+
return std::nullopt;
276+
}
277+
212278
private:
213279
void * _Nonnull opaqueValue = nullptr;
214280
};

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// RUN: %empty-directory(%t)
22

3-
// RUN: %target-swift-frontend %S/swift-functions-errors.swift -typecheck -module-name Functions -clang-header-expose-decls=all-public -emit-clang-header-path %t/functions.h
3+
// RUN: %target-swift-frontend %S/swift-functions-errors.swift -typecheck -module-name Functions -clang-header-expose-decls=has-expose-attr -emit-clang-header-path %t/functions.h
44

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

88
// RUN: %target-codesign %t/swift-functions-errors-execution
@@ -27,7 +27,11 @@ int main() {
2727
try {
2828
Functions::throwFunction();
2929
} catch (swift::Error& e) {
30-
printf("Exception\n");
30+
auto errorVal = e.as<Functions::NaiveErrors, Functions::_impl::_impl_NaiveErrors>();
31+
if (errorVal) {
32+
assert(errorVal == Functions::NaiveErrors::throwError);
33+
errorVal->getMessage();
34+
}
3135
}
3236
try {
3337
Functions::throwFunctionWithReturn();
@@ -43,7 +47,7 @@ int main() {
4347

4448
// CHECK: passEmptyThrowFunction
4549
// CHECK-NEXT: passThrowFunction
46-
// CHECK-NEXT: Exception
50+
// CHECK-NEXT: throwError
4751
// CHECK-NEXT: passThrowFunctionWithReturn
4852
// CHECK-NEXT: Exception
4953
// CHECK-NEXT: Test destroyed

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend %s -typecheck -module-name Functions -clang-header-expose-decls=all-public -emit-clang-header-path %t/functions.h
2+
// RUN: %target-swift-frontend %s -typecheck -module-name Functions -clang-header-expose-decls=has-expose-attr -emit-clang-header-path %t/functions.h
33
// RUN: %FileCheck %s < %t/functions.h
44

55
// RUN: %check-interop-cxx-header-in-clang(%t/functions.h)
@@ -13,11 +13,19 @@
1313

1414
// CHECK: }
1515

16-
enum NaiveErrors : Error {
16+
// XFAIL: *
17+
18+
@_expose(Cxx)
19+
public enum NaiveErrors : Error {
1720
case returnError
1821
case throwError
22+
23+
public func getMessage() {
24+
print(self)
25+
}
1926
}
2027

28+
@_expose(Cxx)
2129
public func emptyThrowFunction() throws { print("passEmptyThrowFunction") }
2230

2331
// CHECK: inline void emptyThrowFunction() {
@@ -34,10 +42,12 @@ class TestDestroyed {
3442
}
3543
}
3644

45+
@_expose(Cxx)
3746
public struct DestroyedError : Error {
3847
let t = TestDestroyed()
3948
}
4049

50+
@_expose(Cxx)
4151
public func testDestroyedError() throws { throw DestroyedError() }
4252

4353
// CHECK: inline void testDestroyedError() {
@@ -48,6 +58,7 @@ public func testDestroyedError() throws { throw DestroyedError() }
4858
// CHECK: throw (swift::Error(opaqueError))
4959
// CHECK: }
5060

61+
@_expose(Cxx)
5162
public func throwFunction() throws {
5263
print("passThrowFunction")
5364
throw NaiveErrors.throwError
@@ -61,6 +72,7 @@ public func throwFunction() throws {
6172
// CHECK: throw (swift::Error(opaqueError))
6273
// CHECK: }
6374

75+
@_expose(Cxx)
6476
public func throwFunctionWithReturn() throws -> Int {
6577
print("passThrowFunctionWithReturn")
6678
throw NaiveErrors.returnError

0 commit comments

Comments
 (0)