Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/PrintAsClang/ModuleContentsWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,7 @@ EmittedClangHeaderDependencyInfo swift::printModuleContentsAsCxx(
os << "#ifndef SWIFT_CXX_INTEROP_HIDE_STL_OVERLAY\n";
os << "#include <string>\n";
os << "#endif\n";
os << "#include <new>\n";
// Embed an overlay for the standard library.
ClangSyntaxPrinter(moduleOS).printIncludeForShimHeader(
"_SwiftStdlibCxxOverlay.h");
Expand Down
44 changes: 38 additions & 6 deletions lib/PrintAsClang/PrintClangFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,8 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature(
ClangRepresentation::representable;

// Print out the return type.
if (FD->hasThrows() && outputLang == OutputLanguageMode::Cxx)
os << "Swift::ThrowingResult<";
if (kind == FunctionSignatureKind::CFunctionProto) {
// First, verify that the C++ return type is representable.
{
Expand Down Expand Up @@ -740,7 +742,8 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature(
.isUnsupported())
return resultingRepresentation;
}

if (FD->hasThrows() && outputLang == OutputLanguageMode::Cxx)
os << ">";
os << ' ';
if (const auto *typeDecl = modifiers.qualifierContext)
ClangSyntaxPrinter(os).printNominalTypeQualifier(
Expand Down Expand Up @@ -1241,14 +1244,43 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
// Create the condition and the statement to throw an exception.
if (hasThrows) {
os << " if (opaqueError != nullptr)\n";
os << "#ifdef __cpp_exceptions\n";
os << " throw (Swift::Error(opaqueError));\n";
}
os << "#else\n";
if (resultTy->isVoid()) {
os << " return SWIFT_RETURN_THUNK(void, Swift::Error(opaqueError));\n";
os << "#endif\n";
} else {
auto directResultType = signature.getDirectResultType();
printDirectReturnOrParamCType(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can extract the return type printing code into a closure in this function, to avoid repeating this code?

*directResultType, resultTy, moduleContext, os, cPrologueOS,
typeMapping, interopContext, [&]() {
os << " return SWIFT_RETURN_THUNK(";
OptionalTypeKind retKind;
Type objTy;
std::tie(objTy, retKind) =
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);

// Return the function result value if it doesn't throw.
if (!resultTy->isVoid() && hasThrows) {
os << "\n";
os << "return returnValue;\n";
auto s = printClangFunctionReturnType(objTy, retKind, const_cast<ModuleDecl *>(moduleContext),
OutputLanguageMode::Cxx);
os << ", Swift::Error(opaqueError));\n";
os << "#endif\n";

// Return the function result value if it doesn't throw.
if (!resultTy->isVoid() && hasThrows) {
os << "\n";
os << " return SWIFT_RETURN_THUNK(";
printClangFunctionReturnType(
objTy, retKind, const_cast<ModuleDecl *>(moduleContext),
OutputLanguageMode::Cxx);
os << ", returnValue);\n";
}

assert(!s.isUnsupported());
});
}
}

}

static StringRef getConstructorName(const AbstractFunctionDecl *FD) {
Expand Down
194 changes: 194 additions & 0 deletions lib/PrintAsClang/_SwiftStdlibCxxOverlay.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ inline const void *_Nullable getErrorMetadata() {
return ptr2;
}

#ifndef SWIFT_CXX_INTEROP_HIDE_SWIFT_ERROR

class Error {
public:
Error() {}
Expand Down Expand Up @@ -179,4 +181,196 @@ class Error {
void *_Nonnull opaqueValue = nullptr;
};

namespace _impl {

constexpr inline std::size_t max(std::size_t a, std::size_t b) {
return a > b ? a : b;
}

} // namespace _impl

/// The Expected class has either an error or an value.
template<class T>
class Expected {
public:

/// Default
constexpr Expected() noexcept {
new (&buffer) Error();
has_val = false;
}

constexpr Expected(const Swift::Error& error_val) noexcept {
new (&buffer) Error(error_val);
has_val = false;
}

constexpr Expected(const T &val) noexcept {
new (&buffer) T(val);
has_val = true;
}

/// Copy
constexpr Expected(Expected const& other) noexcept {
if (other.has_value())
new (&buffer) T(other.value());
else
new (&buffer) Error(other.error());

has_val = other.has_value();
}

/// Move
// FIXME: Implement move semantics when move Swift values is possible
constexpr Expected(Expected&&) noexcept { abort(); }

~Expected() noexcept {
if (has_value())
reinterpret_cast<const T *>(buffer)->~T();
else
reinterpret_cast<Swift::Error *>(buffer)->~Error();
}

/// assignment
constexpr auto operator=(Expected&& other) noexcept = delete;
constexpr auto operator=(Expected&) noexcept = delete;

/// For accessing T's members
constexpr T const *_Nonnull operator->() const noexcept {
if (!has_value())
abort();
return reinterpret_cast<const T *>(buffer);
}

constexpr T *_Nonnull operator->() noexcept {
if (!has_value())
abort();
return reinterpret_cast<T *>(buffer);
}

/// Getting reference to T
constexpr T const &operator*() const & noexcept {
if (!has_value())
abort();
return reinterpret_cast<const T &>(buffer);
}

constexpr T &operator*() & noexcept {
if (!has_value())
abort();
return reinterpret_cast<T &>(buffer);
}

constexpr explicit operator bool() const noexcept { return has_value(); }

// Get value, if not exists abort
constexpr T const& value() const& {
if (!has_value())
abort();
return *reinterpret_cast<const T *>(buffer);
}

constexpr T& value() & {
if (!has_value())
abort();
return *reinterpret_cast<T *>(buffer);
}

// Get error
constexpr Swift::Error const& error() const& {
if (has_value())
abort();
return reinterpret_cast<const Swift::Error&>(buffer);
}

constexpr Swift::Error& error() & {
if (has_value())
abort();
return reinterpret_cast<Swift::Error&>(buffer);
}

constexpr bool has_value() const noexcept { return has_val; }

private:
alignas(_impl::max(alignof(T), alignof(Swift::Error))) char buffer[_impl::max(sizeof(T), sizeof(Swift::Error))];
bool has_val;
};

template<>
class Expected<void> {
public:
/// Default
Expected() noexcept {
new (&buffer) Error();
has_val = false;
}

Expected(const Swift::Error& error_val) noexcept {
new (&buffer) Error(error_val);
has_val = false;
}


/// Copy
Expected(Expected const& other) noexcept {
if (other.has_value())
abort();
else
new (&buffer) Error(other.error());

has_val = other.has_value();
}

/// Move
// FIXME: Implement move semantics when move swift values is possible
[[noreturn]] Expected(Expected&&) noexcept { abort(); }

~Expected() noexcept {
reinterpret_cast<Swift::Error *>(buffer)->~Error();
}

/// assignment
constexpr auto operator=(Expected&& other) noexcept = delete;
constexpr auto operator=(Expected&) noexcept = delete;


constexpr explicit operator bool() const noexcept { return has_value(); }

// Get error
constexpr Swift::Error const& error() const& {
if (has_value())
abort();
return reinterpret_cast<const Swift::Error&>(buffer);
}

constexpr Swift::Error& error() & {
if (has_value())
abort();
return reinterpret_cast<Swift::Error&>(buffer);
}

constexpr bool has_value() const noexcept { return has_val; }
private:
alignas(alignof(Swift::Error)) char buffer[sizeof(Swift::Error)];
bool has_val;
};

#ifdef __cpp_exceptions

template<class T>
using ThrowingResult = T;

#define SWIFT_RETURN_THUNK(T, v) v

#else

template<class T>
using ThrowingResult = Swift::Expected<T>;

#define SWIFT_RETURN_THUNK(T, v) Swift::Expected<T>(v)

#endif

#endif // SWIFT_CXX_INTEROP_HIDE_SWIFT_ERROR

#endif
Loading