mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This patch introduces an a C++ class annotation, SWIFT_PRIVATE_FILEID,
which will specify where Swift extensions of that class will be allowed
to access its non-public members, e.g.:
class SWIFT_PRIVATE_FILEID("MyModule/MyFile.swift") Foo { ... };
The goal of this feature is to help C++ developers incrementally migrate
the implementation of their C++ classes to Swift, without breaking
encapsulation and indiscriminately exposing those classes' private and
protected fields.
As an implementation detail of this feature, this patch introduces an
abstraction for file ID strings, FileIDStr, which represent a parsed pair
of module name/file name.
rdar://137764620
256 lines
10 KiB
Plaintext
256 lines
10 KiB
Plaintext
// -*- C++ -*-
|
|
//===------------------ bridging - C++ and Swift Interop --------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file provides common utilities and annotations that are useful for C++
|
|
// codebases that interoperate with Swift.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#ifndef SWIFT_CLANGIMPORTER_SWIFT_INTEROP_SUPPORT_H
|
|
#define SWIFT_CLANGIMPORTER_SWIFT_INTEROP_SUPPORT_H
|
|
|
|
#ifdef __has_attribute
|
|
#define _CXX_INTEROP_HAS_ATTRIBUTE(x) __has_attribute(x)
|
|
#else
|
|
#define _CXX_INTEROP_HAS_ATTRIBUTE(x) 0
|
|
#endif
|
|
|
|
#if _CXX_INTEROP_HAS_ATTRIBUTE(swift_attr)
|
|
|
|
/// Specifies that a C++ `class` or `struct` owns and controls the lifetime of all
|
|
/// of the objects it references. Such type should not reference any objects whose
|
|
/// lifetime is controlled externally. This annotation allows Swift to import methods
|
|
/// that return a `class` or `struct` type that is annotated with this macro.
|
|
#define SWIFT_SELF_CONTAINED __attribute__((swift_attr("import_owned")))
|
|
|
|
/// Specifies that a C++ method returns a value that is presumed to contain
|
|
/// objects whose lifetime is not dependent on `this` or other parameters passed
|
|
/// to the method.
|
|
#define SWIFT_RETURNS_INDEPENDENT_VALUE __attribute__((swift_attr("import_unsafe")))
|
|
|
|
#define _CXX_INTEROP_STRINGIFY(_x) #_x
|
|
|
|
#define _CXX_INTEROP_CONCAT_(a,b,c,d,e,f,g,i,j,k,l,m,n,o,p,...) \
|
|
#a "," #b "," #c "," #d "," #e "," #f "," #g "," #i "," #j "," #k "," \
|
|
#l "," #m "," #n "," #o "," #p
|
|
#define _CXX_INTEROP_CONCAT(...) \
|
|
_CXX_INTEROP_CONCAT_(__VA_ARGS__,,,,,,,,,,,,,,,,,)
|
|
|
|
/// Specifies that a C++ `class` or `struct` is reference-counted using
|
|
/// the given `retain` and `release` functions. This annotation lets Swift import
|
|
/// such a type as reference counted type in Swift, taking advantage of Swift's
|
|
/// automatic reference counting.
|
|
///
|
|
/// This example shows how to use this macro to let Swift know that
|
|
/// a non-copyable reference counted C++ class can be imported as a reference counted type in Swift:
|
|
/// ```c++
|
|
/// class SWIFT_SHARED_REFERENCE(retainSharedObject, releaseSharedObject)
|
|
/// SharedObject : NonCopyable, IntrusiveReferenceCounted<SharedObject> {
|
|
/// public:
|
|
/// static SharedObject* create();
|
|
/// void doSomething();
|
|
/// };
|
|
///
|
|
/// void retainSharedObject(SharedObject *);
|
|
/// void releaseSharedObject(SharedObject *);
|
|
/// ```
|
|
///
|
|
/// Then, the Swift programmer would be able to use it in the following manner:
|
|
///
|
|
/// ```swift
|
|
/// let object = SharedObject.create()
|
|
/// object.doSomething()
|
|
/// // The Swift compiler will release object here.
|
|
/// ```
|
|
#define SWIFT_SHARED_REFERENCE(_retain, _release) \
|
|
__attribute__((swift_attr("import_reference"))) \
|
|
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(retain:_retain)))) \
|
|
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(release:_release))))
|
|
|
|
/// Specifies that a C++ `class` or `struct` is a reference type whose lifetime
|
|
/// is presumed to be immortal, i.e. the reference to such object is presumed to
|
|
/// always be valid. This annotation lets Swift import such a type as a reference
|
|
/// type in Swift.
|
|
////
|
|
/// This example shows how to use this macro to let Swift know that
|
|
/// a non-copyable singleton C++ class can be imported as a reference type in Swift:
|
|
/// ```c++
|
|
/// class SWIFT_IMMORTAL_REFERENCE
|
|
/// LoggerSingleton : NonCopyable {
|
|
/// public:
|
|
/// static LoggerSingleton &getInstance();
|
|
/// void log(int x);
|
|
/// };
|
|
/// ```
|
|
///
|
|
/// Then, the Swift programmer would be able to use it in the following manner:
|
|
///
|
|
/// ```swift
|
|
/// let logger = LoggerSingleton.getInstance()
|
|
/// logger.log(123)
|
|
/// ```
|
|
#define SWIFT_IMMORTAL_REFERENCE \
|
|
__attribute__((swift_attr("import_reference"))) \
|
|
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(retain:immortal)))) \
|
|
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(release:immortal))))
|
|
|
|
/// Specifies that a C++ `class` or `struct` is a reference type whose lifetime
|
|
/// is not managed automatically. The programmer must validate that any reference
|
|
/// to such object is valid themselves. This annotation lets Swift import such a type as a reference type in Swift.
|
|
#define SWIFT_UNSAFE_REFERENCE \
|
|
__attribute__((swift_attr("import_reference"))) \
|
|
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(retain:immortal)))) \
|
|
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(release:immortal)))) \
|
|
__attribute__((swift_attr("unsafe")))
|
|
|
|
/// Specifies a name that will be used in Swift for this declaration instead of its original name.
|
|
#define SWIFT_NAME(_name) __attribute__((swift_name(#_name)))
|
|
|
|
/// Specifies that a specific C++ `class` or `struct` conforms to a
|
|
/// a specific Swift protocol.
|
|
///
|
|
/// This example shows how to use this macro to conform a class template to a Swift protocol:
|
|
/// ```
|
|
/// template<class T>
|
|
/// class SWIFT_CONFORMS_TO_PROTOCOL(SwiftModule.ProtocolName)
|
|
/// CustomClass {};
|
|
/// ```
|
|
#define SWIFT_CONFORMS_TO_PROTOCOL(_moduleName_protocolName) \
|
|
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(conforms_to:_moduleName_protocolName))))
|
|
|
|
/// Specifies that a specific C++ method should be imported as a computed
|
|
/// property. If this macro is specified on a getter, a getter will be
|
|
/// synthesized. If this macro is specified on a setter, both a getter and
|
|
/// setter will be synthesized.
|
|
///
|
|
/// For example:
|
|
/// ```
|
|
/// int getX() SWIFT_COMPUTED_PROPERTY;
|
|
/// ```
|
|
/// Will be imported as `var x: CInt {...}`.
|
|
#define SWIFT_COMPUTED_PROPERTY \
|
|
__attribute__((swift_attr("import_computed_property")))
|
|
|
|
/// Specifies that a specific **constant** C++ member function should be imported as
|
|
/// `mutating` Swift method. This annotation should be added to constant C++ member functions
|
|
/// that mutate `mutable` fields in a C++ object, to let Swift know that this function is still mutating
|
|
/// and thus that it should become a `mutating` method in Swift.
|
|
#define SWIFT_MUTATING \
|
|
__attribute__((swift_attr("mutating")))
|
|
|
|
/// Specifies that a specific c++ type such class or struct should be imported as type marked
|
|
/// as `@unchecked Sendable` type in swift. If this annotation is used, the type is therefore allowed to
|
|
/// use safely across async contexts.
|
|
///
|
|
/// For example
|
|
/// ```
|
|
/// class SWIFT_UNCHECKED_SENDABLE CustomUserType
|
|
/// { ... }
|
|
/// ```
|
|
/// Will be imported as `struct CustomUserType: @unchecked Sendable`
|
|
#define SWIFT_UNCHECKED_SENDABLE \
|
|
__attribute__((swift_attr("@Sendable")))
|
|
|
|
/// Specifies that a specific c++ type such class or struct should be imported
|
|
/// as a non-copyable Swift value type.
|
|
#define SWIFT_NONCOPYABLE \
|
|
__attribute__((swift_attr("~Copyable")))
|
|
|
|
/// Specifies that a specific c++ type such class or struct should be imported
|
|
/// as a non-escapable Swift value type when the non-escapable language feature
|
|
/// is enabled.
|
|
#define SWIFT_NONESCAPABLE \
|
|
__attribute__((swift_attr("~Escapable")))
|
|
|
|
/// Specifies that a specific c++ type such class or struct should be imported
|
|
/// as a escapable Swift value. While this matches the default behavior,
|
|
/// in safe mode interop mode it ensures that the type is not marked as
|
|
/// unsafe.
|
|
#define SWIFT_ESCAPABLE \
|
|
__attribute__((swift_attr("Escapable")))
|
|
|
|
/// Specifies that a C++ `class` or `struct` should be imported as a escapable
|
|
/// Swift value if all of the specified template arguments are escapable.
|
|
#define SWIFT_ESCAPABLE_IF(...) \
|
|
__attribute__((swift_attr("escapable_if:" _CXX_INTEROP_CONCAT(__VA_ARGS__))))
|
|
|
|
/// Specifies that the return value is passed as owned for C++ functions and
|
|
/// methods returning types annotated as `SWIFT_SHARED_REFERENCE`
|
|
#define SWIFT_RETURNS_RETAINED __attribute__((swift_attr("returns_retained")))
|
|
/// Specifies that the return value is passed as unowned for C++ functions and
|
|
/// methods returning types annotated as `SWIFT_SHARED_REFERENCE`
|
|
#define SWIFT_RETURNS_UNRETAINED \
|
|
__attribute__((swift_attr("returns_unretained")))
|
|
|
|
/// Specifies that the non-public members of a C++ class, struct, or union can
|
|
/// be accessed from extensions of that type, in the given file ID.
|
|
///
|
|
/// In other words, Swift's access controls will behave as if the non-public
|
|
/// members of the annotated C++ class were privated declared in the specified
|
|
/// Swift source file, rather than in a C++ header file/Clang module.
|
|
///
|
|
/// For example, we can annotate a C++ class definition like this:
|
|
///
|
|
/// ```c++
|
|
/// class SWIFT_PRIVATE_FILEID("MySwiftModule/MySwiftFile.swift")
|
|
/// MyCxxClass {
|
|
/// private:
|
|
/// void privateMethod();
|
|
/// int privateStorage;
|
|
/// };
|
|
/// ```
|
|
///
|
|
/// Then, Swift extensions of `MyCxxClass` in `MySwiftModule/MySwiftFile.swift`
|
|
/// are allowed to access `privateMethod()` and `privateStorage`:
|
|
///
|
|
/// ```swift
|
|
/// //-- MySwiftModule/SwiftFile.swift
|
|
/// extension MyCxxClass {
|
|
/// func ext() {
|
|
/// privateMethod()
|
|
/// print("\(privateStorage)")
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// Non-public access is still forbidden outside of extensions and outside of
|
|
/// the designated file ID.
|
|
#define SWIFT_PRIVATE_FILEID(_fileID) \
|
|
__attribute__((swift_attr("private_fileid:" _fileID)))
|
|
|
|
#else // #if _CXX_INTEROP_HAS_ATTRIBUTE(swift_attr)
|
|
|
|
// Empty defines for compilers that don't support `attribute(swift_attr)`.
|
|
#define SWIFT_SELF_CONTAINED
|
|
#define SWIFT_RETURNS_INDEPENDENT_VALUE
|
|
#define SWIFT_SHARED_REFERENCE(_retain, _release)
|
|
#define SWIFT_IMMORTAL_REFERENCE
|
|
#define SWIFT_UNSAFE_REFERENCE
|
|
#define SWIFT_NAME(_name)
|
|
#define SWIFT_CONFORMS_TO_PROTOCOL(_moduleName_protocolName)
|
|
#define SWIFT_COMPUTED_PROPERTY
|
|
#define SWIFT_MUTATING
|
|
#define SWIFT_UNCHECKED_SENDABLE
|
|
#define SWIFT_NONCOPYABLE
|
|
#define SWIFT_NONESCAPABLE
|
|
#define SWIFT_ESCAPABLE
|
|
#define SWIFT_ESCAPABLE_IF(...)
|
|
#define SWIFT_RETURNS_RETAINED
|
|
#define SWIFT_RETURNS_UNRETAINED
|
|
#define SWIFT_PRIVATE_FILEID(_fileID)
|
|
|
|
#endif // #if _CXX_INTEROP_HAS_ATTRIBUTE(swift_attr)
|
|
|
|
#undef _CXX_INTEROP_HAS_ATTRIBUTE
|
|
|
|
#endif // SWIFT_CLANGIMPORTER_SWIFT_INTEROP_SUPPORT_H
|