Skip to content
Merged
3 changes: 2 additions & 1 deletion lib/PrintAsClang/ModuleContentsWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,8 @@ class ModuleWriter {

SmallVector<ProtocolConformance *, 1> conformances;
auto errorTypeProto = ctx.getProtocol(KnownProtocolKind::Error);
if (ED->lookupConformance(errorTypeProto, conformances)) {
if (outputLangMode != OutputLanguageMode::Cxx
&& ED->lookupConformance(errorTypeProto, conformances)) {
bool hasDomainCase = std::any_of(ED->getAllElements().begin(),
ED->getAllElements().end(),
[](const EnumElementDecl *elem) {
Expand Down
66 changes: 66 additions & 0 deletions lib/PrintAsClang/_SwiftCxxInteroperability.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
#if defined(_WIN32)
#include <malloc.h>
#endif
#if !defined(SWIFT_CALL)
# define SWIFT_CALL __attribute__((swiftcall))
#endif

// FIXME: Use always_inline, artificial.
#define SWIFT_INLINE_THUNK inline
Expand Down Expand Up @@ -191,6 +194,46 @@ extern "C" void *_Nonnull swift_errorRetain(void *_Nonnull swiftError) noexcept;

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

extern "C" int $ss5ErrorMp; // external global %swift.protocol, align 4

extern "C"
const void * _Nullable
swift_getTypeByMangledNameInContext(
const char *_Nullable typeNameStart,
size_t typeNameLength,
const void *_Nullable context,
const void *_Nullable const *_Nullable genericArgs) SWIFT_CALL;

extern "C" bool swift_dynamicCast(void *_Nullable dest, void *_Nullable src,
const void *_Nullable srcType,
const void * _Nullable targetType,
uint32_t flags);

struct SymbolicP {
alignas(2) uint8_t _1;
uint32_t _2;
uint8_t _3[2];
uint8_t _4;
} __attribute__((packed));

inline const void *_Nullable getErrorMetadata() {
static swift::SymbolicP errorSymbol;
static int *_Nonnull got_ss5ErrorMp = &$ss5ErrorMp;
errorSymbol._1 = 2;
errorSymbol._2 = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&got_ss5ErrorMp) - reinterpret_cast<uintptr_t>(&errorSymbol._2));
errorSymbol._3[0] = '_';
errorSymbol._3[1] = 'p';
errorSymbol._4 = 0;
static_assert(sizeof(errorSymbol) == 8, "");
auto charErrorSymbol = reinterpret_cast<const char *>(&errorSymbol);

const void *ptr2 =
swift::swift_getTypeByMangledNameInContext(charErrorSymbol,
sizeof(errorSymbol) - 1,
nullptr, nullptr);
return ptr2;
}

class Error {
public:
Error() {}
Expand All @@ -209,6 +252,29 @@ class Error {
opaqueValue = other.opaqueValue;
}

// FIXME: Return a Swift::Optional instead.
template<class T>
T as() {
alignas(alignof(T)) char buffer[sizeof(T)];
const void *em = getErrorMetadata();
void *ep = getPointerToOpaquePointer();
auto metadata = swift::TypeMetadataTrait<T>::getTypeMetadata();

// Dynamic cast will release the error, so we need to retain it.
swift::swift_errorRetain(ep);
bool dynamicCast =
swift::swift_dynamicCast(buffer, &ep, em, metadata,
/*take on success destroy on failure*/ 6);

if (dynamicCast) {
return swift::_impl::implClassFor<T>::type::returnNewValue([&](char *dest) {
swift::_impl::implClassFor<T>::type::initializeWithTake(dest, buffer);
});
}
abort();
// FIXME: return nil.
}

private:
void * _Nonnull opaqueValue = nullptr;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %empty-directory(%t)

// 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
// 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

// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-functions-errors-execution.o
// 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
Expand All @@ -9,6 +9,7 @@
// RUN: %target-run %t/swift-functions-errors-execution | %FileCheck %s

// REQUIRES: executable_test
// UNSUPPORTED: OS=windows-msvc

#include <cassert>
#include <cstdio>
Expand All @@ -27,7 +28,9 @@ int main() {
try {
Functions::throwFunction();
} catch (swift::Error& e) {
printf("Exception\n");
auto errorVal = e.as<Functions::NaiveErrors>();
assert(errorVal == Functions::NaiveErrors::throwError);
errorVal.getMessage();
}
try {
Functions::throwFunctionWithReturn();
Expand All @@ -43,7 +46,7 @@ int main() {

// CHECK: passEmptyThrowFunction
// CHECK-NEXT: passThrowFunction
// CHECK-NEXT: Exception
// CHECK-NEXT: throwError
// CHECK-NEXT: passThrowFunctionWithReturn
// CHECK-NEXT: Exception
// CHECK-NEXT: Test destroyed
// CHECK-NEXT: Test destroyed
14 changes: 12 additions & 2 deletions test/Interop/SwiftToCxx/functions/swift-functions-errors.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Functions -clang-header-expose-decls=all-public -emit-clang-header-path %t/functions.h
// RUN: %target-swift-frontend %s -typecheck -module-name Functions -clang-header-expose-decls=has-expose-attr -emit-clang-header-path %t/functions.h
// RUN: %FileCheck %s < %t/functions.h

// RUN: %check-interop-cxx-header-in-clang(%t/functions.h)
Expand All @@ -13,11 +13,17 @@

// CHECK: }

enum NaiveErrors : Error {
@_expose(Cxx)
public enum NaiveErrors : Error {
case returnError
case throwError

public func getMessage() {
print(self)
}
}

@_expose(Cxx)
public func emptyThrowFunction() throws { print("passEmptyThrowFunction") }

// CHECK: inline void emptyThrowFunction() {
Expand All @@ -34,10 +40,12 @@ class TestDestroyed {
}
}

@_expose(Cxx)
public struct DestroyedError : Error {
let t = TestDestroyed()
}

@_expose(Cxx)
public func testDestroyedError() throws { throw DestroyedError() }

// CHECK: inline void testDestroyedError() {
Expand All @@ -48,6 +56,7 @@ public func testDestroyedError() throws { throw DestroyedError() }
// CHECK: throw (swift::Error(opaqueError))
// CHECK: }

@_expose(Cxx)
public func throwFunction() throws {
print("passThrowFunction")
throw NaiveErrors.throwError
Expand All @@ -61,6 +70,7 @@ public func throwFunction() throws {
// CHECK: throw (swift::Error(opaqueError))
// CHECK: }

@_expose(Cxx)
public func throwFunctionWithReturn() throws -> Int {
print("passThrowFunctionWithReturn")
throw NaiveErrors.returnError
Expand Down