mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
320 lines
11 KiB
C++
320 lines
11 KiB
C++
//===--- _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 <cstdint>
|
|
#include <stdlib.h>
|
|
#if defined(_WIN32)
|
|
#include <malloc.h>
|
|
#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<char *>(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<char *_Nonnull>(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<char *_Nonnull>(storage);
|
|
}
|
|
SWIFT_INLINE_THUNK const char *_Nonnull getOpaquePointer() const noexcept {
|
|
return static_cast<char *_Nonnull>(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 <class T>
|
|
static inline const constexpr bool isUsableInGenericContext = false;
|
|
|
|
/// Returns the type metadata for the given Swift type T.
|
|
template <class T> struct TypeMetadataTrait {
|
|
static SWIFT_INLINE_THUNK void *_Nonnull getTypeMetadata();
|
|
};
|
|
|
|
namespace _impl {
|
|
|
|
/// Type trait that returns the `_impl::_impl_<T>` class type for the given
|
|
/// class T.
|
|
template <class T> struct implClassFor {
|
|
// using type = ...;
|
|
};
|
|
|
|
/// True if the given type is a Swift value type.
|
|
template <class T> 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 <class T> 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 <class T>
|
|
static inline const constexpr bool isSwiftBridgedCxxRecord = false;
|
|
|
|
/// Returns the opaque pointer to the given value.
|
|
template <class T>
|
|
SWIFT_INLINE_THUNK const void *_Nonnull getOpaquePointer(const T &value) {
|
|
if constexpr (isOpaqueLayout<T>)
|
|
return reinterpret_cast<const OpaqueStorage &>(value).getOpaquePointer();
|
|
return reinterpret_cast<const void *>(&value);
|
|
}
|
|
|
|
template <class T>
|
|
SWIFT_INLINE_THUNK void *_Nonnull getOpaquePointer(T &value) {
|
|
if constexpr (isOpaqueLayout<T>)
|
|
return reinterpret_cast<OpaqueStorage &>(value).getOpaquePointer();
|
|
return reinterpret_cast<void *>(&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 T> class ConsumedValueStorageDestroyer {
|
|
public:
|
|
SWIFT_INLINE_THUNK ConsumedValueStorageDestroyer(T &val) noexcept
|
|
: value(val) {}
|
|
SWIFT_INLINE_THUNK ~ConsumedValueStorageDestroyer() noexcept {
|
|
if constexpr (isOpaqueLayout<T>)
|
|
reinterpret_cast<OpaqueStorage &>(value).~OpaqueStorage();
|
|
}
|
|
|
|
private:
|
|
T &value;
|
|
};
|
|
|
|
} // namespace _impl
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
} // namespace swift SWIFT_PRIVATE_ATTR
|
|
#endif
|
|
|
|
#endif // SWIFT_CXX_INTEROPERABILITY_H
|