// RUN: %empty-directory(%t) // RUN: split-file %s %t // RUN: %target-swift-frontend %t/use-cxx-types.swift -module-name UseCxxTy -typecheck -verify -emit-clang-header-path %t/UseCxxTy.h -I %t -enable-experimental-cxx-interop -clang-header-expose-decls=all-public -disable-availability-checking // RUN: %FileCheck %s --input-file %t/UseCxxTy.h // RUN: %target-swift-frontend %t/use-cxx-types.swift -module-name UseCxxTy -typecheck -verify -emit-clang-header-path %t/UseCxxTyExposeOnly.h -I %t -enable-experimental-cxx-interop -clang-header-expose-decls=has-expose-attr -disable-availability-checking // RUN: %FileCheck %s --input-file %t/UseCxxTyExposeOnly.h // FIXME: remove once https://github.com/apple/swift/pull/60971 lands. // RUN: echo "#include \"header.h\"" > %t/full-cxx-swift-cxx-bridging.h // RUN: cat %t/UseCxxTy.h >> %t/full-cxx-swift-cxx-bridging.h // RUN: %check-interop-cxx-header-in-clang(%t/full-cxx-swift-cxx-bridging.h -Wno-reserved-identifier) // Check that the generated header can be // built with Clang modules enabled in C++. // RUN: %target-interop-build-clangxx -fsyntax-only -x c++-header %t/full-cxx-swift-cxx-bridging.h -std=gnu++17 -c -fmodules -fcxx-modules -I %t // FIXME: test c++20 (rdar://117419434) //--- header.h struct Trivial { short x, y; }; namespace ns { struct TrivialinNS { short x, y; }; template struct NonTrivialTemplate { T x; NonTrivialTemplate(); NonTrivialTemplate(const NonTrivialTemplate &other) : x(other.x) {} NonTrivialTemplate(NonTrivialTemplate &&) = default; ~NonTrivialTemplate() {} }; using TypeAlias = NonTrivialTemplate; struct NonTrivialImplicitMove { NonTrivialTemplate member; NonTrivialImplicitMove(const NonTrivialImplicitMove &other) : member(other.member) {} }; #define IMMORTAL_REF \ __attribute__((swift_attr("import_as_ref"))) \ __attribute__((swift_attr("retain:immortal"))) \ __attribute__((swift_attr("release:immortal"))) struct IMMORTAL_REF Immortal { public: }; inline Immortal *makeNewImmortal() { return new Immortal; } template struct IMMORTAL_REF ImmortalTemplate { public: }; inline ImmortalTemplate *makeNewImmortalInt() { return new ImmortalTemplate; } using ImmortalCInt = ImmortalTemplate; using NonTrivialTemplateInt = NonTrivialTemplate; using NonTrivialTemplateTrivial = NonTrivialTemplate; } using SimpleTypedef = int; typedef struct { float column; } anonymousStruct; namespace ns { using anonStructInNS = struct { float row; }; } enum class SimpleScopedEnum { x = 0, y = 2 }; typedef SimpleScopedEnum SimpleScopedEnumTypedef; //--- module.modulemap module CxxTest { header "header.h" requires cplusplus } //--- use-cxx-types.swift import CxxTest @_expose(Cxx) public func retImmortal() -> ns.Immortal { return ns.makeNewImmortal() } @_expose(Cxx) public func retImmortalTemplate() -> ns.ImmortalCInt { return ns.makeNewImmortalInt() } @_expose(Cxx) public func retNonTrivial() -> ns.NonTrivialTemplateInt { return ns.NonTrivialTemplateInt() } @_expose(Cxx) public func retNonTrivial2() -> ns.NonTrivialTemplateTrivial { return ns.NonTrivialTemplateTrivial() } @_expose(Cxx) public func retNonTrivialImplicitMove() -> ns.NonTrivialImplicitMove { return ns.NonTrivialImplicitMove() } @_expose(Cxx) public func retNonTrivialTypeAlias() -> ns.TypeAlias { return ns.TypeAlias() } @_expose(Cxx) public func retSimpleScopedEnum() -> SimpleScopedEnum { return .x } @_expose(Cxx) public func retSimpleScopedEnumTypedef() -> SimpleScopedEnumTypedef { return .x } @_expose(Cxx) public func retSimpleTypedef() -> SimpleTypedef { return SimpleTypedef() } @_expose(Cxx) public func retTrivial() -> Trivial { return Trivial() } @_expose(Cxx) public func takeImmortal(_ x: ns.Immortal) { } @_expose(Cxx) public func takeImmortalTemplate(_ x: ns.ImmortalCInt) { } @_expose(Cxx) public func takeNonTrivial2(_ x: ns.NonTrivialTemplateTrivial) { } @_expose(Cxx) public func takeSimpleScopedEnum(_ x: SimpleScopedEnum) { } @_expose(Cxx) public func takeTrivial(_ x: Trivial) { } @_expose(Cxx) public func takeTrivialInout(_ x: inout Trivial) { } @_expose(Cxx) public struct Strct { public let transform: anonymousStruct public let transform2: ns.anonStructInNS } // CHECK: #if __has_feature(objc_modules) // CHECK: #if __has_feature(objc_modules) // CHECK-NEXT: #if __has_warning("-Watimport-in-framework-header") // CHECK-NEXT: #pragma clang diagnostic ignored "-Watimport-in-framework-header" // CHECK-NEXT:#endif // CHECK-NEXT: #pragma clang module import CxxTest // CHECK-NEXT: #endif // CHECK: SWIFT_EXTERN void $s8UseCxxTy13retNonTrivialSo2nsO0030NonTrivialTemplateCInt_hHAFhrbVyF(SWIFT_INDIRECT_RESULT void * _Nonnull) SWIFT_NOEXCEPT SWIFT_CALL; // retNonTrivial() // CHECK: SWIFT_EXTERN struct swift_interop_returnStub_UseCxxTy_uint32_t_0_4 $s8UseCxxTy10retTrivialSo0E0VyF(void) SWIFT_NOEXCEPT SWIFT_CALL; // retTrivial() // CHECK: ns::Immortal *_Nonnull retImmortal() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT { // CHECK-NEXT: return UseCxxTy::_impl::$s8UseCxxTy11retImmortalSo2nsO0E0VyF(); // CHECK-NEXT: } // CHECK: ns::ImmortalTemplate *_Nonnull retImmortalTemplate() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT { // CHECK-NEXT: return UseCxxTy::_impl::$s8UseCxxTy19retImmortalTemplateSo2nsO0028ImmortalTemplateCInt_jBAGgnbVyF(); // CHECK-NEXT: } // CHECK-EMPTY: // CHECK-NEXT: namespace _impl { // CHECK-EMPTY: // CHECK-NEXT: // Type metadata accessor for NonTrivialTemplateInt // CHECK-NEXT: SWIFT_EXTERN swift::_impl::MetadataResponseTy $sSo2nsO0030NonTrivialTemplateCInt_hHAFhrbVMa(swift::_impl::MetadataRequestTy) SWIFT_NOEXCEPT SWIFT_CALL; // CHECK-EMPTY: // CHECK-EMPTY: // CHECK-NEXT: } // namespace _impl // CHECK-EMPTY: // CHECK-NEXT: } // end namespace // CHECK-EMPTY: // CHECK-NEXT: namespace swift SWIFT_PRIVATE_ATTR { // CHECK-NEXT: #pragma clang diagnostic push // CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions" // CHECK-NEXT: template<> // CHECK-NEXT: inline const constexpr bool isUsableInGenericContext = true; // CHECK-NEXT: template<> // CHECK-NEXT: struct TypeMetadataTrait { // CHECK-NEXT: static SWIFT_INLINE_PRIVATE_HELPER void * _Nonnull getTypeMetadata() { // CHECK-NEXT: return UseCxxTy::_impl::$sSo2nsO0030NonTrivialTemplateCInt_hHAFhrbVMa(0)._0; // CHECK-NEXT: } // CHECK-NEXT: }; // CHECK-NEXT: namespace _impl{ // CHECK-NEXT: template<> // CHECK-NEXT: inline const constexpr bool isSwiftBridgedCxxRecord = true; // CHECK-NEXT: } // namespace // CHECK-NEXT: #pragma clang diagnostic pop // CHECK-NEXT: } // namespace swift // CHECK-EMPTY: // CHECK-NEXT: namespace UseCxxTy SWIFT_PRIVATE_ATTR SWIFT_SYMBOL_MODULE("UseCxxTy") { // CHECK: SWIFT_INLINE_THUNK ns::NonTrivialTemplate retNonTrivial() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT { // CHECK-NEXT: alignas(alignof(ns::NonTrivialTemplate)) char storage[sizeof(ns::NonTrivialTemplate)]; // CHECK-NEXT: auto * _Nonnull storageObjectPtr = reinterpret_cast *>(storage); // CHECK-NEXT: _impl::$s8UseCxxTy13retNonTrivialSo2nsO0030NonTrivialTemplateCInt_hHAFhrbVyF(storage); // CHECK-NEXT: ns::NonTrivialTemplate result(static_cast &&>(*storageObjectPtr)); // CHECK-NEXT: storageObjectPtr->~NonTrivialTemplate(); // CHECK-NEXT: return result; // CHECK-NEXT: } // CHECK-EMPTY: // CHECK-NEXT: namespace _impl { // CHECK-EMPTY: // CHECK-NEXT: // Type metadata accessor for NonTrivialTemplateTrivial // CHECK-NEXT: SWIFT_EXTERN swift::_impl::MetadataResponseTy $sSo2nsO0042NonTrivialTemplatensTrivialinNS_HlGFlenawcVMa(swift::_impl::MetadataRequestTy) SWIFT_NOEXCEPT SWIFT_CALL; // CHECK-EMPTY: // CHECK-EMPTY: // CHECK-NEXT: } // namespace _impl // CHECK-EMPTY: // CHECK-NEXT: } // end namespace // CHECK-EMPTY: // CHECK-NEXT: namespace swift SWIFT_PRIVATE_ATTR { // CHECK-NEXT: #pragma clang diagnostic push // CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions" // CHECK-NEXT: template<> // CHECK-NEXT: inline const constexpr bool isUsableInGenericContext = true; // CHECK-NEXT: template<> // CHECK-NEXT: struct TypeMetadataTrait { // CHECK-NEXT: static SWIFT_INLINE_PRIVATE_HELPER void * _Nonnull getTypeMetadata() { // CHECK-NEXT: return UseCxxTy::_impl::$sSo2nsO0042NonTrivialTemplatensTrivialinNS_HlGFlenawcVMa(0)._0; // CHECK-NEXT: } // CHECK-NEXT: }; // CHECK-NEXT: namespace _impl{ // CHECK-NEXT: template<> // CHECK-NEXT: inline const constexpr bool isSwiftBridgedCxxRecord = true; // CHECK-NEXT: } // namespace // CHECK-NEXT: #pragma clang diagnostic pop // CHECK-NEXT: } // namespace swift // CHECK-EMPTY: // CHECK-NEXT: namespace UseCxxTy SWIFT_PRIVATE_ATTR SWIFT_SYMBOL_MODULE("UseCxxTy") { // CHECK-NEXT: SWIFT_INLINE_THUNK ns::NonTrivialTemplate retNonTrivial2() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT { // CHECK-NEXT: alignas(alignof(ns::NonTrivialTemplate)) char storage[sizeof(ns::NonTrivialTemplate)]; // CHECK-NEXT: auto * _Nonnull storageObjectPtr = reinterpret_cast *>(storage); // CHECK-NEXT: _impl::$s8UseCxxTy14retNonTrivial2So2nsO0042NonTrivialTemplatensTrivialinNS_HlGFlenawcVyF(storage); // CHECK-NEXT: ns::NonTrivialTemplate result(static_cast &&>(*storageObjectPtr)); // CHECK-NEXT: storageObjectPtr->~NonTrivialTemplate(); // CHECK-NEXT: return result; // CHECK-NEXT: } // CHECK: SWIFT_INLINE_THUNK ns::NonTrivialImplicitMove retNonTrivialImplicitMove() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT { // CHECK-NEXT: alignas(alignof(ns::NonTrivialImplicitMove)) char storage[sizeof(ns::NonTrivialImplicitMove)]; // CHECK-NEXT: auto * _Nonnull storageObjectPtr = reinterpret_cast(storage); // CHECK-NEXT: _impl::$s8UseCxxTy25retNonTrivialImplicitMoveSo2nsO0efgH0VyF(storage); // CHECK-NEXT: ns::NonTrivialImplicitMove result(static_cast(*storageObjectPtr)); // CHECK-NEXT: storageObjectPtr->~NonTrivialImplicitMove(); // CHECK-NEXT: return result; // CHECK-NEXT: } // CHECK: ns::NonTrivialTemplate retNonTrivialTypeAlias() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT { // CHECK: SimpleScopedEnum retSimpleScopedEnum() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT { // FIXME: Would we prefer to print these with the typedef names? // CHECK: SimpleScopedEnum retSimpleScopedEnumTypedef() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT { // CHECK: int32_t retSimpleTypedef() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT { // CHECK: SWIFT_INLINE_THUNK Trivial retTrivial() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT { // CHECK-NEXT: alignas(alignof(Trivial)) char storage[sizeof(Trivial)]; // CHECK-NEXT: auto * _Nonnull storageObjectPtr = reinterpret_cast(storage); // CHECK-NEXT: UseCxxTy::_impl::swift_interop_returnDirect_UseCxxTy_uint32_t_0_4(storage, UseCxxTy::_impl::$s8UseCxxTy10retTrivialSo0E0VyF()); // CHECK-NEXT: return *storageObjectPtr; // CHECK-NEXT: } // CHECK: void takeImmortal(ns::Immortal *_Nonnull x) noexcept SWIFT_SYMBOL({{.*}}) { // CHECK-NEXT: _impl::$s8UseCxxTy12takeImmortalyySo2nsO0E0VF(x); // CHECK-NEXT: } // CHECK: void takeImmortalTemplate(ns::ImmortalTemplate *_Nonnull x) noexcept SWIFT_SYMBOL({{.*}}) { // CHECK-NEXT: _impl::$s8UseCxxTy20takeImmortalTemplateyySo2nsO0028ImmortalTemplateCInt_jBAGgnbVF(x); // CHECK-NEXT: } // CHECK: SWIFT_INLINE_THUNK void takeNonTrivial2(const ns::NonTrivialTemplate& x) noexcept SWIFT_SYMBOL({{.*}}) { // CHECK-NEXT: _impl::$s8UseCxxTy15takeNonTrivial2yySo2nsO0042NonTrivialTemplatensTrivialinNS_HlGFlenawcVF(swift::_impl::getOpaquePointer(x)); // CHECK-NEXT: } // CHECK: SWIFT_INLINE_THUNK void takeSimpleScopedEnum(const SimpleScopedEnum& x) noexcept SWIFT_SYMBOL({{.*}}) { // CHECK: SWIFT_INLINE_THUNK void takeTrivial(const Trivial& x) noexcept SWIFT_SYMBOL({{.*}}) { // CHECK-NEXT: _impl::$s8UseCxxTy11takeTrivialyySo0E0VF(UseCxxTy::_impl::swift_interop_passDirect_UseCxxTy_uint32_t_0_4(reinterpret_cast(swift::_impl::getOpaquePointer(x)))); // CHECK-NEXT: } // CHECK: SWIFT_INLINE_THUNK void takeTrivialInout(Trivial& x) noexcept SWIFT_SYMBOL({{.*}}) { // CHECK-NEXT: _impl::$s8UseCxxTy16takeTrivialInoutyySo0E0VzF(swift::_impl::getOpaquePointer(x)); // CHECK-NEXT: } // CHECK: SWIFT_INLINE_THUNK anonymousStruct Strct::getTransform() const { // CHECK-NEXT: alignas(alignof(anonymousStruct)) char storage[sizeof(anonymousStruct)]; // CHECK: SWIFT_INLINE_THUNK ns::anonStructInNS Strct::getTransform2() const { // CHECK-NEXT: alignas(alignof(ns::anonStructInNS)) char storage[sizeof(ns::anonStructInNS)];