//===--- _SwiftCxxInteroperability.h - C++ Interop support ------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // Defines types and support functions required by C++ bindings generated // by the Swift compiler that allow C++ code to call Swift APIs. // //===----------------------------------------------------------------------===// #ifndef SWIFT_CXX_INTEROPERABILITY_H #define SWIFT_CXX_INTEROPERABILITY_H #ifdef __cplusplus #include #include #if defined(_WIN32) #include #endif #if !defined(SWIFT_CALL) # define SWIFT_CALL __attribute__((swiftcall)) #endif #if __has_attribute(transparent_stepping) #define SWIFT_INLINE_THUNK_ATTRIBUTES \ __attribute__((transparent_stepping)) #elif __has_attribute(always_inline) && __has_attribute(nodebug) #define SWIFT_INLINE_THUNK_ATTRIBUTES \ __attribute__((always_inline)) __attribute__((nodebug)) #else #define SWIFT_INLINE_THUNK_ATTRIBUTES #endif #if defined(DEBUG) && __has_attribute(used) // Additional 'used' attribute is used in debug mode to make inline thunks // accessible to LLDB. #define SWIFT_INLINE_THUNK_USED_ATTRIBUTE __attribute__((used)) #else #define SWIFT_INLINE_THUNK_USED_ATTRIBUTE #endif /// The `SWIFT_INLINE_THUNK` macro is applied on the inline function thunks in /// the header that represents a C/C++ Swift module interface generated by the /// Swift compiler. #define SWIFT_INLINE_THUNK \ inline SWIFT_INLINE_THUNK_ATTRIBUTES SWIFT_INLINE_THUNK_USED_ATTRIBUTE /// The `SWIFT_INLINE_PRIVATE_HELPER` macro is applied on the helper / utility /// functions in the header that represents a C/C++ Swift module interface /// generated by the Swift compiler. #define SWIFT_INLINE_PRIVATE_HELPER inline SWIFT_INLINE_THUNK_ATTRIBUTES /// The `SWIFT_SYMBOL_MODULE` and `SWIFT_SYMBOL_MODULE_USR` macros apply /// `external_source_symbol` Clang attributes to C++ declarations that represent /// Swift declarations. This allows Clang to index them as external /// declarations, using the specified Swift USR values. #if __has_attribute(external_source_symbol) #define SWIFT_SYMBOL_MODULE(moduleValue) \ __attribute__((external_source_symbol( \ language = "Swift", defined_in = moduleValue, generated_declaration))) #if __has_attribute(external_source_symbol) > 1 #define SWIFT_SYMBOL_MODULE_USR(moduleValue, usrValue) \ __attribute__(( \ external_source_symbol(language = "Swift", defined_in = moduleValue, \ generated_declaration, USR = usrValue))) #else #define SWIFT_SYMBOL_MODULE_USR(moduleValue, usrValue) \ __attribute__((external_source_symbol( \ language = "Swift", defined_in = moduleValue, generated_declaration))) #endif #else #define SWIFT_SYMBOL_MODULE_USR(moduleValue, usrValue) #define SWIFT_SYMBOL_MODULE(moduleValue) #endif #if __has_attribute(swift_private) #define SWIFT_PRIVATE_ATTR __attribute__((swift_private)) #else #define SWIFT_PRIVATE_ATTR #endif namespace swift SWIFT_PRIVATE_ATTR { namespace _impl { extern "C" void *_Nonnull swift_retain(void *_Nonnull) noexcept; extern "C" void swift_release(void *_Nonnull) noexcept; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-identifier" extern "C" void _swift_stdlib_reportFatalError(const char *_Nonnull prefix, int prefixLength, const char *_Nonnull message, int messageLength, uint32_t flags) noexcept; // A dummy symbol that forces a linker error when // C++ tries to invoke a move of a Swift value type. extern "C" void _fatalError_Cxx_move_of_Swift_value_type_not_supported_yet(); #pragma clang diagnostic pop SWIFT_INLINE_THUNK void *_Nonnull opaqueAlloc(size_t size, size_t align) noexcept { #if defined(SWIFT_CXX_INTEROPERABILITY_OVERRIDE_OPAQUE_STORAGE_alloc) && \ defined(SWIFT_CXX_INTEROPERABILITY_OVERRIDE_OPAQUE_STORAGE_free) // Allow the user to provide custom allocator for heap-allocated Swift // value types. return SWIFT_CXX_INTEROPERABILITY_OVERRIDE_OPAQUE_STORAGE_alloc(size, align); #else #if defined(_WIN32) void *r = _aligned_malloc(size, align); #else if (align < sizeof(void *)) align = sizeof(void *); void *r = nullptr; int res = posix_memalign(&r, align, size); (void)res; #endif return r; #endif } SWIFT_INLINE_THUNK void opaqueFree(void *_Nonnull p) noexcept { #if defined(SWIFT_CXX_INTEROPERABILITY_OVERRIDE_OPAQUE_STORAGE_alloc) && \ defined(SWIFT_CXX_INTEROPERABILITY_OVERRIDE_OPAQUE_STORAGE_free) // Allow the user to provide custom allocator for heap-allocated Swift // value types. SWIFT_CXX_INTEROPERABILITY_OVERRIDE_OPAQUE_STORAGE_free(p); #else #if defined(_WIN32) _aligned_free(p); #else free(p); #endif #endif } /// Base class for a container for an opaque Swift value, like resilient struct. class OpaqueStorage { public: SWIFT_INLINE_THUNK OpaqueStorage() noexcept : storage(nullptr) {} SWIFT_INLINE_THUNK OpaqueStorage(size_t size, size_t alignment) noexcept : storage(reinterpret_cast(opaqueAlloc(size, alignment))) {} SWIFT_INLINE_THUNK OpaqueStorage(OpaqueStorage &&other) noexcept : storage(other.storage) { other.storage = nullptr; } OpaqueStorage(const OpaqueStorage &) noexcept = delete; SWIFT_INLINE_THUNK ~OpaqueStorage() noexcept { if (storage) { opaqueFree(static_cast(storage)); } } SWIFT_INLINE_THUNK void operator=(OpaqueStorage &&other) noexcept { auto temp = storage; storage = other.storage; other.storage = temp; } void operator=(const OpaqueStorage &) noexcept = delete; SWIFT_INLINE_THUNK char *_Nonnull getOpaquePointer() noexcept { return static_cast(storage); } SWIFT_INLINE_THUNK const char *_Nonnull getOpaquePointer() const noexcept { return static_cast(storage); } private: char *_Nullable storage; }; /// Base class for a Swift reference counted class value. class RefCountedClass { public: SWIFT_INLINE_THUNK ~RefCountedClass() { swift_release(_opaquePointer); } SWIFT_INLINE_THUNK RefCountedClass(const RefCountedClass &other) noexcept : _opaquePointer(other._opaquePointer) { swift_retain(_opaquePointer); } SWIFT_INLINE_THUNK RefCountedClass(RefCountedClass &&other) noexcept : _opaquePointer(other._opaquePointer) { // Moving a Swift class reference is a copy // in C++. This allows C++ to avoid liveness // checks to see if the pointer is `null` or not, // as C++'s move is not consuming, unlike Swift's. swift_retain(_opaquePointer); } SWIFT_INLINE_THUNK RefCountedClass & operator=(const RefCountedClass &other) noexcept { swift_retain(other._opaquePointer); swift_release(_opaquePointer); _opaquePointer = other._opaquePointer; return *this; } SWIFT_INLINE_THUNK RefCountedClass & operator=(RefCountedClass &&other) noexcept { swift_retain(other._opaquePointer); swift_release(_opaquePointer); _opaquePointer = other._opaquePointer; return *this; } protected: SWIFT_INLINE_THUNK RefCountedClass(void *_Nonnull ptr) noexcept : _opaquePointer(ptr) {} private: void *_Nonnull _opaquePointer; friend class _impl_RefCountedClass; }; class _impl_RefCountedClass { public: static SWIFT_INLINE_THUNK void *_Nonnull getOpaquePointer( const RefCountedClass &object) { return object._opaquePointer; } static SWIFT_INLINE_THUNK void *_Nonnull & getOpaquePointerRef(RefCountedClass &object) { return object._opaquePointer; } static SWIFT_INLINE_THUNK void *_Nonnull copyOpaquePointer( const RefCountedClass &object) { swift_retain(object._opaquePointer); return object._opaquePointer; } }; } // namespace _impl /// Swift's Int type. using Int = ptrdiff_t; /// Swift's UInt type. using UInt = size_t; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wc++17-extensions" /// True if the given type is a Swift type that can be used in a generic context /// in Swift. template static inline const constexpr bool isUsableInGenericContext = false; /// Returns the type metadata for the given Swift type T. template struct TypeMetadataTrait { static SWIFT_INLINE_THUNK void *_Nonnull getTypeMetadata(); }; namespace _impl { /// Type trait that returns the `_impl::_impl_` class type for the given /// class T. template struct implClassFor { // using type = ...; }; /// True if the given type is a Swift value type. template static inline const constexpr bool isValueType = false; /// True if the given type is a Swift value type with opaque layout that can be /// boxed. template static inline const constexpr bool isOpaqueLayout = false; /// True if the given type is a C++ record that was bridged to Swift, giving /// Swift ability to work with it in a generic context. template static inline const constexpr bool isSwiftBridgedCxxRecord = false; /// Returns the opaque pointer to the given value. template SWIFT_INLINE_THUNK const void *_Nonnull getOpaquePointer(const T &value) { if constexpr (isOpaqueLayout) return reinterpret_cast(value).getOpaquePointer(); return reinterpret_cast(&value); } template SWIFT_INLINE_THUNK void *_Nonnull getOpaquePointer(T &value) { if constexpr (isOpaqueLayout) return reinterpret_cast(value).getOpaquePointer(); return reinterpret_cast(&value); } /// Helper struct that destroys any additional storage allocated (e.g. for /// resilient value types) for a Swift value owned by C++ code after the Swift /// value was consumed and thus the original C++ destructor is not ran. template class ConsumedValueStorageDestroyer { public: SWIFT_INLINE_THUNK ConsumedValueStorageDestroyer(T &val) noexcept : value(val) {} SWIFT_INLINE_THUNK ~ConsumedValueStorageDestroyer() noexcept { if constexpr (isOpaqueLayout) reinterpret_cast(value).~OpaqueStorage(); } private: T &value; }; } // namespace _impl #pragma clang diagnostic pop } // namespace swift SWIFT_PRIVATE_ATTR #endif #endif // SWIFT_CXX_INTEROPERABILITY_H