diff --git a/include/swift/IRGen/IRABIDetailsProvider.h b/include/swift/IRGen/IRABIDetailsProvider.h index 26398c021fcfc..b3edd7fc9a18a 100644 --- a/include/swift/IRGen/IRABIDetailsProvider.h +++ b/include/swift/IRGen/IRABIDetailsProvider.h @@ -96,13 +96,16 @@ class LoweredFunctionSignature { inline const ParamDecl &getParamDecl() const { return paramDecl; } + inline ParameterConvention getConvention() const { return convention; } + private: DirectParameter(IRABIDetailsProviderImpl &owner, const irgen::TypeInfo &typeDetails, - const ParamDecl ¶mDecl); + const ParamDecl ¶mDecl, ParameterConvention convention); IRABIDetailsProviderImpl &owner; const irgen::TypeInfo &typeDetails; const ParamDecl ¶mDecl; + ParameterConvention convention; friend class LoweredFunctionSignature; }; @@ -111,9 +114,13 @@ class LoweredFunctionSignature { public: inline const ParamDecl &getParamDecl() const { return paramDecl; } + inline ParameterConvention getConvention() const { return convention; } + private: - IndirectParameter(const ParamDecl ¶mDecl); + IndirectParameter(const ParamDecl ¶mDecl, + ParameterConvention convention); const ParamDecl ¶mDecl; + ParameterConvention convention; friend class LoweredFunctionSignature; }; diff --git a/lib/IRGen/IRABIDetailsProvider.cpp b/lib/IRGen/IRABIDetailsProvider.cpp index d00516614bdba..1bf98bd926a69 100644 --- a/lib/IRGen/IRABIDetailsProvider.cpp +++ b/lib/IRGen/IRABIDetailsProvider.cpp @@ -313,12 +313,13 @@ bool LoweredFunctionSignature::DirectResultType::enumerateRecordMembers( LoweredFunctionSignature::DirectParameter::DirectParameter( IRABIDetailsProviderImpl &owner, const irgen::TypeInfo &typeDetails, - const ParamDecl ¶mDecl) - : owner(owner), typeDetails(typeDetails), paramDecl(paramDecl) {} + const ParamDecl ¶mDecl, ParameterConvention convention) + : owner(owner), typeDetails(typeDetails), paramDecl(paramDecl), + convention(convention) {} LoweredFunctionSignature::IndirectParameter::IndirectParameter( - const ParamDecl ¶mDecl) - : paramDecl(paramDecl) {} + const ParamDecl ¶mDecl, ParameterConvention convention) + : paramDecl(paramDecl), convention(convention) {} bool LoweredFunctionSignature::DirectParameter::enumerateRecordMembers( llvm::function_ref callback) @@ -401,10 +402,11 @@ void LoweredFunctionSignature::visitParameterList( : silParamMapping[currentSilParam]; ++currentSilParam; if (!isIndirect) { - DirectParameter param(owner, abiParam.typeInfo, *paramDecl); + DirectParameter param(owner, abiParam.typeInfo, *paramDecl, + abiParam.convention); directParamVisitor(param); } else { - IndirectParameter param(*paramDecl); + IndirectParameter param(*paramDecl, abiParam.convention); indirectParamVisitor(param); } } @@ -432,8 +434,11 @@ void LoweredFunctionSignature::visitParameterList( if (abiDetails.hasTrailingSelfParam) { assert(!abiDetails.hasContextParam); - assert(FD->hasImplicitSelfDecl()); - indirectParamVisitor(IndirectParameter(*FD->getImplicitSelfDecl())); + indirectParamVisitor(IndirectParameter( + *FD->getImplicitSelfDecl(), + FD->getImplicitSelfDecl()->getValueOwnership() == ValueOwnership::Owned + ? ParameterConvention::Direct_Owned + : ParameterConvention::Direct_Guaranteed)); } else if (abiDetails.hasContextParam) { contextParamVisitor(ContextParameter()); } diff --git a/lib/PrintAsClang/PrintClangFunction.cpp b/lib/PrintAsClang/PrintClangFunction.cpp index 19c0d3cffcd54..604d7b1e85bf6 100644 --- a/lib/PrintAsClang/PrintClangFunction.cpp +++ b/lib/PrintAsClang/PrintClangFunction.cpp @@ -30,6 +30,7 @@ #include "swift/ClangImporter/ClangImporter.h" #include "swift/IRGen/IRABIDetailsProvider.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclObjC.h" #include "llvm/ADT/STLExtras.h" @@ -281,6 +282,25 @@ class CFunctionSignatureTypePrinter os << " __strong"; printInoutTypeModifier(); } + if (isa(cd->getClangDecl())) { + if (std::find_if( + cd->getClangDecl()->getAttrs().begin(), + cd->getClangDecl()->getAttrs().end(), [](clang::Attr *attr) { + if (auto *sa = dyn_cast(attr)) { + llvm::StringRef value = sa->getAttribute(); + if ((value.startswith("retain:") || + value.startswith("release:")) && + !value.endswith(":immortal")) + return true; + } + return false; + }) != cd->getClangDecl()->getAttrs().end()) { + // This is a shared FRT. Do not bridge it back to + // C++ as its ownership is not managed automatically + // in C++ yet. + return ClangRepresentation::unsupported; + } + } // FIXME: Mark that this is only ObjC representable. return ClangRepresentation::representable; } @@ -966,7 +986,7 @@ void DeclAndTypeClangFunctionPrinter::printTypeImplTypeSpecifier( void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse( Type type, StringRef name, const ModuleDecl *moduleContext, bool isInOut, - bool isIndirect, std::string directTypeEncoding, bool isSelf) { + bool isIndirect, std::string directTypeEncoding, bool forceSelf) { auto namePrinter = [&]() { ClangSyntaxPrinter(os).printIdentifier(name); }; if (!isKnownCxxType(type, typeMapping) && !hasKnownOptionalNullableCxxMapping(type)) { @@ -1007,9 +1027,9 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse( } else { ClangValueTypePrinter(os, cPrologueOS, interopContext) .printParameterCxxToCUseScaffold( - moduleContext, - [&]() { printTypeImplTypeSpecifier(type, moduleContext); }, - namePrinter, isSelf); + moduleContext, + [&]() { printTypeImplTypeSpecifier(type, moduleContext); }, + namePrinter, forceSelf); } if (!directTypeEncoding.empty()) os << ')'; @@ -1153,6 +1173,82 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody( break; } } + + auto getParamName = [&](const ParamDecl ¶m, size_t paramIndex, + bool isConsumed) { + std::string paramName; + if (isConsumed) + paramName = "consumedParamCopy_"; + if (param.isSelfParameter()) { + if (isConsumed) + paramName += "this"; + else + paramName = "*this"; + } else if (param.getName().empty()) { + llvm::raw_string_ostream paramOS(paramName); + if (!isConsumed) + paramOS << "_"; + paramOS << paramIndex; + } else { + StringRef nameStr = param.getName().str(); + if (isConsumed) + paramName += nameStr.str(); + else + paramName = nameStr; + renameCxxParameterIfNeeded(FD, paramName); + } + return paramName; + }; + + // Check if we need to copy any parameters that are consumed by Swift, + // to ensure that Swift does not destroy the value that's owned by C++. + // FIXME: Support non-copyable types here as well between C++ -> Swift. + // FIXME: class types can be optimized down to an additional retain right + // here. + size_t paramIndex = 1; + auto emitParamCopyForConsume = [&](const ParamDecl ¶m) { + auto name = getParamName(param, paramIndex, /*isConsumed=*/false); + auto consumedName = getParamName(param, paramIndex, /*isConsumed=*/true); + std::string paramType; + + llvm::raw_string_ostream typeOS(paramType); + + CFunctionSignatureTypePrinter typePrinter( + typeOS, cPrologueOS, typeMapping, OutputLanguageMode::Cxx, + interopContext, CFunctionSignatureTypePrinterModifierDelegate(), + moduleContext, declPrinter, FunctionSignatureTypeUse::TypeReference); + auto result = typePrinter.visit(param.getInterfaceType(), OTK_None, + /*isInOutParam=*/false); + assert(!result.isUnsupported()); + typeOS.flush(); + + os << " alignas(alignof(" << paramType << ")) char copyBuffer_" + << consumedName << "[sizeof(" << paramType << ")];\n"; + os << " auto &" << consumedName << " = *(new(copyBuffer_" << consumedName + << ") " << paramType << "(" << name << "));\n"; + os << " swift::" << cxx_synthesis::getCxxImplNamespaceName() + << "::ConsumedValueStorageDestroyer<" << paramType << "> storageGuard_" + << consumedName << "(" << consumedName << ");\n"; + }; + signature.visitParameterList( + [&](const LoweredFunctionSignature::IndirectResultValue &) {}, + [&](const LoweredFunctionSignature::DirectParameter ¶m) { + if (isConsumedParameter(param.getConvention())) + emitParamCopyForConsume(param.getParamDecl()); + ++paramIndex; + }, + [&](const LoweredFunctionSignature::IndirectParameter ¶m) { + if (isConsumedParameter(param.getConvention())) + emitParamCopyForConsume(param.getParamDecl()); + ++paramIndex; + }, + [&](const LoweredFunctionSignature::GenericRequirementParameter + &genericRequirementParam) {}, + [&](const LoweredFunctionSignature::MetadataSourceParameter + &metadataSrcParam) {}, + [&](const LoweredFunctionSignature::ContextParameter &) {}, + [&](const LoweredFunctionSignature::ErrorResultValue &) {}); + auto printCallToCFunc = [&](llvm::Optional additionalParam) { if (indirectFunctionVar) os << "(* " << *indirectFunctionVar << ')'; @@ -1168,13 +1264,14 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody( needsComma = true; }; auto printParamUse = [&](const ParamDecl ¶m, bool isIndirect, + bool isConsumed, std::string directTypeEncoding) { emitNewParam(); - std::string paramName; if (param.isSelfParameter()) { bool needsStaticSelf = isa(FD) || isStaticMethod; if (needsStaticSelf) { + // Static self value is just the type's metadata value. os << "swift::TypeMetadataTrait<"; CFunctionSignatureTypePrinter typePrinter( os, cPrologueOS, typeMapping, OutputLanguageMode::Cxx, @@ -1187,19 +1284,13 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody( os << ">::getTypeMetadata()"; return; } - paramName = "*this"; - } else if (param.getName().empty()) { - llvm::raw_string_ostream paramOS(paramName); - paramOS << "_" << paramIndex; - } else { - paramName = param.getName().str().str(); - renameCxxParameterIfNeeded(FD, paramName); } + auto paramName = getParamName(param, paramIndex, isConsumed); ++paramIndex; printCxxToCFunctionParameterUse(param.getInterfaceType(), paramName, param.getModuleContext(), param.isInOut(), isIndirect, directTypeEncoding, - param.isSelfParameter()); + !isConsumed && param.isSelfParameter()); }; signature.visitParameterList( @@ -1211,10 +1302,12 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody( }, [&](const LoweredFunctionSignature::DirectParameter ¶m) { printParamUse(param.getParamDecl(), /*isIndirect=*/false, + isConsumedParameter(param.getConvention()), encodeTypeInfo(param, moduleContext, typeMapping)); }, [&](const LoweredFunctionSignature::IndirectParameter ¶m) { printParamUse(param.getParamDecl(), /*isIndirect=*/true, + isConsumedParameter(param.getConvention()), /*directTypeEncoding=*/""); }, [&](const LoweredFunctionSignature::GenericRequirementParameter diff --git a/lib/PrintAsClang/PrintClangValueType.cpp b/lib/PrintAsClang/PrintClangValueType.cpp index 2fe99f0e1a4db..37a1433ba4b3c 100644 --- a/lib/PrintAsClang/PrintClangValueType.cpp +++ b/lib/PrintAsClang/PrintClangValueType.cpp @@ -502,16 +502,16 @@ void ClangValueTypePrinter::printValueTypeDecl( if (!isOpaqueLayout) printCValueTypeStorageStruct(cPrologueOS, typeDecl, *typeSizeAlign); - printTypeGenericTraits(os, typeDecl, typeMetadataFuncName, - typeMetadataFuncGenericParams, - typeDecl->getModuleContext(), declAndTypePrinter); + printTypeGenericTraits( + os, typeDecl, typeMetadataFuncName, typeMetadataFuncGenericParams, + typeDecl->getModuleContext(), declAndTypePrinter, isOpaqueLayout); } void ClangValueTypePrinter::printParameterCxxToCUseScaffold( const ModuleDecl *moduleContext, llvm::function_ref typePrinter, - llvm::function_ref cxxParamPrinter, bool isSelf) { + llvm::function_ref cxxParamPrinter, bool forceSelf) { // A Swift value type is passed to its underlying Swift function - if (isSelf) { + if (forceSelf) { os << "_getOpaquePointer()"; } else { // FIXME: can we propagate the _impl request here? @@ -581,14 +581,27 @@ void ClangValueTypePrinter::printTypePrecedingGenericTraits( os << "#pragma clang diagnostic push\n"; os << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n"; - if (!typeDecl->isGeneric()) { - // FIXME: generic type support. + + if (printer.printNominalTypeOutsideMemberDeclTemplateSpecifiers(typeDecl)) os << "template<>\n"; - os << "static inline const constexpr bool isUsableInGenericContext<"; - printer.printNominalTypeReference(typeDecl, - /*moduleContext=*/nullptr); - os << "> = true;\n"; - } + os << "static inline const constexpr bool isUsableInGenericContext<"; + printer.printNominalTypeReference(typeDecl, + /*moduleContext=*/nullptr); + os << "> = "; + if (typeDecl->isGeneric()) { + auto signature = typeDecl->getGenericSignature().getCanonicalSignature(); + llvm::interleave( + signature.getInnermostGenericParams(), os, + [&](const GenericTypeParamType *genericParamType) { + os << "isUsableInGenericContext<"; + printer.printGenericTypeParamTypeName(genericParamType); + os << '>'; + }, + " && "); + } else + os << "true"; + os << ";\n"; + os << "#pragma clang diagnostic pop\n"; os << "} // namespace swift\n"; os << "\n"; @@ -598,7 +611,8 @@ void ClangValueTypePrinter::printTypePrecedingGenericTraits( void ClangValueTypePrinter::printTypeGenericTraits( raw_ostream &os, const TypeDecl *typeDecl, StringRef typeMetadataFuncName, ArrayRef typeMetadataFuncRequirements, - const ModuleDecl *moduleContext, DeclAndTypePrinter &declAndTypePrinter) { + const ModuleDecl *moduleContext, DeclAndTypePrinter &declAndTypePrinter, + bool isOpaqueLayout) { auto *NTD = dyn_cast(typeDecl); ClangSyntaxPrinter printer(os); // FIXME: avoid popping out of the module's namespace here. @@ -668,14 +682,16 @@ void ClangValueTypePrinter::printTypeGenericTraits( os << "::"; printer.printBaseName(typeDecl); os << "> = true;\n"; - if (NTD && NTD->isResilient()) { + } + if (isOpaqueLayout) { + assert(NTD && "not a nominal type?"); + assert(!isa(typeDecl) && !typeDecl->hasClangNode()); + if (printer.printNominalTypeOutsideMemberDeclTemplateSpecifiers(NTD)) os << "template<>\n"; - os << "static inline const constexpr bool isOpaqueLayout<"; - printer.printBaseName(typeDecl->getModuleContext()); - os << "::"; - printer.printBaseName(typeDecl); - os << "> = true;\n"; - } + os << "static inline const constexpr bool isOpaqueLayout<"; + printer.printNominalTypeReference(NTD, + /*moduleContext=*/nullptr); + os << "> = true;\n"; } // FIXME: generic support. diff --git a/lib/PrintAsClang/PrintClangValueType.h b/lib/PrintAsClang/PrintClangValueType.h index f857acb14c742..e1625ccb3d909 100644 --- a/lib/PrintAsClang/PrintClangValueType.h +++ b/lib/PrintAsClang/PrintClangValueType.h @@ -96,7 +96,8 @@ class ClangValueTypePrinter { static void printTypeGenericTraits( raw_ostream &os, const TypeDecl *typeDecl, StringRef typeMetadataFuncName, ArrayRef typeMetadataFuncRequirements, - const ModuleDecl *moduleContext, DeclAndTypePrinter &declAndTypePrinter); + const ModuleDecl *moduleContext, DeclAndTypePrinter &declAndTypePrinter, + bool isOpaqueLayout = false); static void printTypePrecedingGenericTraits(raw_ostream &os, const NominalTypeDecl *typeDecl, diff --git a/lib/PrintAsClang/_SwiftCxxInteroperability.h b/lib/PrintAsClang/_SwiftCxxInteroperability.h index e09017b126f6a..49137c529a23a 100644 --- a/lib/PrintAsClang/_SwiftCxxInteroperability.h +++ b/lib/PrintAsClang/_SwiftCxxInteroperability.h @@ -110,6 +110,12 @@ extern "C" void _fatalError_Cxx_move_of_Swift_value_type_not_supported_yet(); 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 @@ -120,14 +126,22 @@ SWIFT_INLINE_THUNK void *_Nonnull opaqueAlloc(size_t 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. @@ -279,6 +293,22 @@ SWIFT_INLINE_THUNK void *_Nonnull getOpaquePointer(T &value) { 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 diff --git a/test/Interop/CxxToSwiftToCxx/consuming-cxx-struct-parameter-back-to-cxx-execution.cpp b/test/Interop/CxxToSwiftToCxx/consuming-cxx-struct-parameter-back-to-cxx-execution.cpp new file mode 100644 index 0000000000000..b9b369fbe2668 --- /dev/null +++ b/test/Interop/CxxToSwiftToCxx/consuming-cxx-struct-parameter-back-to-cxx-execution.cpp @@ -0,0 +1,126 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-swift-frontend -typecheck %t/use-cxx-types.swift -typecheck -module-name UseCxx -emit-clang-header-path %t/UseCxx.h -I %t -enable-experimental-cxx-interop -clang-header-expose-decls=all-public -disable-availability-checking + +// RUN: %target-interop-build-clangxx -std=c++20 -c %t/use-swift-cxx-types.cpp -I %t -o %t/swift-cxx-execution.o +// RUN: %target-interop-build-swift %t/use-cxx-types.swift -o %t/swift-cxx-execution -Xlinker %t/swift-cxx-execution.o -module-name UseCxx -Xfrontend -entry-point-function-name -Xfrontend swiftMain -I %t -O -Xfrontend -disable-availability-checking + +// RUN: %target-codesign %t/swift-cxx-execution +// RUN: %target-run %t/swift-cxx-execution | %FileCheck %s + +// REQUIRES: executable_test + +//--- header.h + +#include + +struct Trivial { + int x, y; + + inline Trivial(int x, int y) : x(x), y(y) {} +}; + +template +struct NonTrivialTemplate { + T x; + + inline NonTrivialTemplate(T x) : x(x) { + puts("create NonTrivialTemplate"); + } + inline NonTrivialTemplate(const NonTrivialTemplate &other) : x(other.x) { + puts("copy NonTrivialTemplate"); + } + inline NonTrivialTemplate(NonTrivialTemplate &&other) : x(static_cast(other.x)) { + puts("move NonTrivialTemplate"); + } + inline ~NonTrivialTemplate() { + puts("~NonTrivialTemplate"); + } + inline void testPrint() const { + puts("testPrint"); + } +}; + +using NonTrivialTemplateTrivial = NonTrivialTemplate; + +class ImmortalFRT { +public: + int x; +} __attribute__((swift_attr("import_reference"))) +__attribute__((swift_attr("retain:immortal"))) +__attribute__((swift_attr("release:immortal"))); + +//--- module.modulemap +module CxxTest { + header "header.h" + requires cplusplus +} + +//--- use-cxx-types.swift +import CxxTest + +public func consumeNonTrivial(_ x: consuming NonTrivialTemplateTrivial) -> CInt { + print("x and y: \(x.x.x), \(x.x.y)") + return x.x.x +} + +public struct TakesNonTrivial { + public init(_ x: NonTrivialTemplateTrivial) { + self.prop = x + } + + public var prop: NonTrivialTemplateTrivial +} + +public func consumeImmortalFRT(_ x: consuming ImmortalFRT) { + print("frt x \(x.x)") +} + +//--- use-swift-cxx-types.cpp + +#include "header.h" +#include "UseCxx.h" +#include + +int main() { + { + auto x = NonTrivialTemplate(Trivial(1, 2)); + UseCxx::consumeNonTrivial(x); + puts("DoneCall"); + } +// CHECK: create NonTrivialTemplate +// CHECK-NEXT: copy NonTrivialTemplate +// CHECK-NEXT: x and y: 1, 2 +// CHECK-NEXT: ~NonTrivialTemplate +// CHECK-NEXT: DoneCall +// CHECK-NEXT: ~NonTrivialTemplate + { + auto x = NonTrivialTemplate(Trivial(-4, 0)); + puts("call"); + auto swiftVal = UseCxx::TakesNonTrivial::init(x); + puts("DoneCall"); + swiftVal.setProp(x); + } +// CHECK-NEXT: create NonTrivialTemplate +// CHECK-NEXT: call +// CHECK-NEXT: copy NonTrivialTemplate +// CHECK-NEXT: copy NonTrivialTemplate +// CHECK-NEXT: ~NonTrivialTemplate +// CHECK-NEXT: DoneCall +// CHECK-NEXT: copy NonTrivialTemplate +// CHECK-NEXT: ~NonTrivialTemplate +// CHECK-NEXT: copy NonTrivialTemplate +// CHECK-NEXT: ~NonTrivialTemplate +// CHECK-NEXT: ~NonTrivialTemplate +// CHECK-NEXT: ~NonTrivialTemplate + { + ImmortalFRT frt; + frt.x = 2; + UseCxx::consumeImmortalFRT(&frt); + } +// CHECK-NEXT: frt x 2 + puts("EndOfTest"); +// CHECK-NEXT: EndOfTest + return 0; +} diff --git a/test/Interop/CxxToSwiftToCxx/disallow-shared-frt-back-to-cxx.swift b/test/Interop/CxxToSwiftToCxx/disallow-shared-frt-back-to-cxx.swift new file mode 100644 index 0000000000000..462132427aafa --- /dev/null +++ b/test/Interop/CxxToSwiftToCxx/disallow-shared-frt-back-to-cxx.swift @@ -0,0 +1,34 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-swift-frontend -typecheck %t/use-cxx-types.swift -typecheck -module-name UseCxxTy -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 < %t/UseCxxTy.h + +//--- header.h + +class SharedFRT { +public: + int x; +} __attribute__((swift_attr("import_reference"))) +__attribute__((swift_attr("retain:retainShared"))) +__attribute__((swift_attr("release:releaseShared"))); + +inline void retainShared(SharedFRT *r) { } +inline void releaseShared(SharedFRT *r) { } + +//--- module.modulemap +module CxxTest { + header "header.h" + requires cplusplus +} + +//--- use-cxx-types.swift +import CxxTest + +public func consumeSharedFRT(_ x: consuming SharedFRT) {} +public func takeSharedFRT(_ x: SharedFRT) {} + +// CHECK: Unavailable in C++: Swift global function 'consumeSharedFRT(_:)'. + +// CHECK: Unavailable in C++: Swift global function 'takeSharedFRT(_:)'. diff --git a/test/Interop/SwiftToCxx/generics/generic-enum-in-cxx.swift b/test/Interop/SwiftToCxx/generics/generic-enum-in-cxx.swift index 463a709deaaa5..64b4739dac64d 100644 --- a/test/Interop/SwiftToCxx/generics/generic-enum-in-cxx.swift +++ b/test/Interop/SwiftToCxx/generics/generic-enum-in-cxx.swift @@ -95,6 +95,12 @@ public func inoutConcreteOpt(_ x: inout GenericOpt) { // CHECK-NEXT: #endif // CHECK-NEXT: class SWIFT_SYMBOL("s:8Generics10GenericOptO") GenericOpt; +// CHECK: template +// CHECK-NEXT: #ifdef __cpp_concepts +// CHECK-NEXT: requires swift::isUsableInGenericContext +// CHECK-NEXT: #endif +// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext> = isUsableInGenericContext; + // CHECK: template // CHECK-NEXT: #ifdef __cpp_concepts // CHECK-NEXT: requires swift::isUsableInGenericContext diff --git a/test/Interop/SwiftToCxx/generics/generic-struct-in-cxx.swift b/test/Interop/SwiftToCxx/generics/generic-struct-in-cxx.swift index b9be02f228a30..0bf941623af99 100644 --- a/test/Interop/SwiftToCxx/generics/generic-struct-in-cxx.swift +++ b/test/Interop/SwiftToCxx/generics/generic-struct-in-cxx.swift @@ -206,6 +206,12 @@ public func inoutConcretePair(_ x: UInt16, _ y: inout GenericPair +// CHECK-NEXT: #ifdef __cpp_concepts +// CHECK-NEXT: requires swift::isUsableInGenericContext && swift::isUsableInGenericContext +// CHECK-NEXT: #endif // __cpp_concepts +// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext> = isUsableInGenericContext && isUsableInGenericContext; + // CHECK: template // CHECK-NEXT: #ifdef __cpp_concepts // CHECK-NEXT: requires swift::isUsableInGenericContext && swift::isUsableInGenericContext @@ -274,6 +280,11 @@ public func inoutConcretePair(_ x: UInt16, _ y: inout GenericPair +// CHECK-NEXT: #ifdef __cpp_concepts +// CHECK-NEXT: requires swift::isUsableInGenericContext && swift::isUsableInGenericContext +// CHECK-NEXT: #endif // __cpp_concepts +// CHECK-NEXT: static inline const constexpr bool isOpaqueLayout> = true; // CHECK-NEXT: } // namespace // CHECK-NEXT: #pragma clang diagnostic pop // CHECK-NEXT: } // namespace swift @@ -380,7 +391,10 @@ public func inoutConcretePair(_ x: UInt16, _ y: inout GenericPair, "type cannot be used in a Swift generic context"); // CHECK-NEXT: static_assert(swift::isUsableInGenericContext, "type cannot be used in a Swift generic context"); // CHECK-NEXT: #endif -// CHECK-NEXT: return _impl::$s8Generics11GenericPairV1yq_vs(swift::_impl::getOpaquePointer(value), swift::TypeMetadataTrait>::getTypeMetadata(), _getOpaquePointer()); +// CHECK-NEXT: alignas(alignof(T_0_1)) char copyBuffer_consumedParamCopy_value[sizeof(T_0_1)]; +// CHECK-NEXT: auto &consumedParamCopy_value = *(new(copyBuffer_consumedParamCopy_value) T_0_1(value)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_value(consumedParamCopy_value); +// CHECK-NEXT: return _impl::$s8Generics11GenericPairV1yq_vs(swift::_impl::getOpaquePointer(consumedParamCopy_value), swift::TypeMetadataTrait>::getTypeMetadata(), _getOpaquePointer()); // CHECK-NEXT: } // CHECK-NEXT: template // CHECK-NEXT: #ifdef __cpp_concepts @@ -391,8 +405,14 @@ public func inoutConcretePair(_ x: UInt16, _ y: inout GenericPair, "type cannot be used in a Swift generic context"); // CHECK-NEXT: static_assert(swift::isUsableInGenericContext, "type cannot be used in a Swift generic context"); // CHECK-NEXT: #endif +// CHECK-NEXT: alignas(alignof(T_0_0)) char copyBuffer_consumedParamCopy_x[sizeof(T_0_0)]; +// CHECK-NEXT: auto &consumedParamCopy_x = *(new(copyBuffer_consumedParamCopy_x) T_0_0(x)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_x(consumedParamCopy_x); +// CHECK-NEXT: alignas(alignof(T_0_1)) char copyBuffer_consumedParamCopy_y[sizeof(T_0_1)]; +// CHECK-NEXT: auto &consumedParamCopy_y = *(new(copyBuffer_consumedParamCopy_y) T_0_1(y)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_y(consumedParamCopy_y); // CHECK-NEXT: return _impl::_impl_GenericPair::returnNewValue([&](char * _Nonnull result) SWIFT_INLINE_THUNK_ATTRIBUTES { -// CHECK-NEXT: _impl::$s8Generics11GenericPairVyACyxq_Gx_Siq_tcfC(result, swift::_impl::getOpaquePointer(x), i, swift::_impl::getOpaquePointer(y), swift::TypeMetadataTrait::getTypeMetadata(), swift::TypeMetadataTrait::getTypeMetadata()); +// CHECK-NEXT: _impl::$s8Generics11GenericPairVyACyxq_Gx_Siq_tcfC(result, swift::_impl::getOpaquePointer(consumedParamCopy_x), i, swift::_impl::getOpaquePointer(consumedParamCopy_y), swift::TypeMetadataTrait::getTypeMetadata(), swift::TypeMetadataTrait::getTypeMetadata()); // CHECK-NEXT: }); // CHECK-NEXT: } // CHECK-NEXT: template @@ -470,4 +490,7 @@ public func inoutConcretePair(_ x: UInt16, _ y: inout GenericPair, "type cannot be used in a Swift generic context"); // CHECK-NEXT: static_assert(swift::isUsableInGenericContext, "type cannot be used in a Swift generic context"); // CHECK-NEXT: #endif -// CHECK-NEXT: return _impl::$s8Generics11GenericPairV11computedVarxvs(swift::_impl::getOpaquePointer(newValue), swift::TypeMetadataTrait>::getTypeMetadata(), _getOpaquePointer()); +// CHECK-NEXT: alignas(alignof(T_0_0)) char copyBuffer_consumedParamCopy_newValue[sizeof(T_0_0)]; +// CHECK-NEXT: auto &consumedParamCopy_newValue = *(new(copyBuffer_consumedParamCopy_newValue) T_0_0(newValue)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_newValue(consumedParamCopy_newValue); +// CHECK-NEXT: return _impl::$s8Generics11GenericPairV11computedVarxvs(swift::_impl::getOpaquePointer(consumedParamCopy_newValue), swift::TypeMetadataTrait>::getTypeMetadata(), _getOpaquePointer()); diff --git a/test/Interop/SwiftToCxx/generics/generic-struct-known-layout-direct-in-cxx.swift b/test/Interop/SwiftToCxx/generics/generic-struct-known-layout-direct-in-cxx.swift index 4ebf07e71a803..24662caf11b5c 100644 --- a/test/Interop/SwiftToCxx/generics/generic-struct-known-layout-direct-in-cxx.swift +++ b/test/Interop/SwiftToCxx/generics/generic-struct-known-layout-direct-in-cxx.swift @@ -76,6 +76,7 @@ // CHECK-NEXT: #endif // CHECK-NEXT: class SWIFT_SYMBOL("s:8Generics11GenericPairV") GenericPair; +// CHECK: template // CHECK: template // CHECK: template // CHECK-NEXT: #ifdef __cpp_concepts @@ -154,15 +155,24 @@ // CHECK-NEXT: static_assert(swift::isUsableInGenericContext, "type cannot be used in a Swift generic context"); // CHECK-NEXT: static_assert(swift::isUsableInGenericContext, "type cannot be used in a Swift generic context"); // CHECK-NEXT: #endif -// CHECK-NEXT: return _impl::$s8Generics11GenericPairV1yq_vs(swift::_impl::getOpaquePointer(newValue), swift::TypeMetadataTrait>::getTypeMetadata(), _getOpaquePointer()); +// CHECK-NEXT: alignas(alignof(T_0_1)) char copyBuffer_consumedParamCopy_newValue[sizeof(T_0_1)]; +// CHECK-NEXT: auto &consumedParamCopy_newValue = *(new(copyBuffer_consumedParamCopy_newValue) T_0_1(newValue)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_newValue(consumedParamCopy_newValue); +// CHECK-NEXT: return _impl::$s8Generics11GenericPairV1yq_vs(swift::_impl::getOpaquePointer(consumedParamCopy_newValue), swift::TypeMetadataTrait>::getTypeMetadata(), _getOpaquePointer()); // CHECK: SWIFT_INLINE_THUNK GenericPair GenericPair::init(const T_0_0& x, swift::Int i, const T_0_1& y) // CHECK-NEXT: #ifndef __cpp_concepts // CHECK-NEXT: static_assert(swift::isUsableInGenericContext, "type cannot be used in a Swift generic context"); // CHECK-NEXT: static_assert(swift::isUsableInGenericContext, "type cannot be used in a Swift generic context"); // CHECK-NEXT: #endif +// CHECK-NEXT: alignas(alignof(T_0_0)) char copyBuffer_consumedParamCopy_x[sizeof(T_0_0)]; +// CHECK-NEXT: auto &consumedParamCopy_x = *(new(copyBuffer_consumedParamCopy_x) T_0_0(x)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_x(consumedParamCopy_x); +// CHECK-NEXT: alignas(alignof(T_0_1)) char copyBuffer_consumedParamCopy_y[sizeof(T_0_1)]; +// CHECK-NEXT: auto &consumedParamCopy_y = *(new(copyBuffer_consumedParamCopy_y) T_0_1(y)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_y(consumedParamCopy_y); // CHECK-NEXT: return _impl::_impl_GenericPair::returnNewValue([&](char * _Nonnull result) SWIFT_INLINE_THUNK_ATTRIBUTES { -// CHECK-NEXT: _impl::swift_interop_returnDirect_Generics_[[PTRPTRENC]](result, _impl::$s8Generics11GenericPairVyACyxq_Gx_Siq_tcfC(swift::_impl::getOpaquePointer(x), i, swift::_impl::getOpaquePointer(y), swift::TypeMetadataTrait::getTypeMetadata(), swift::TypeMetadataTrait::getTypeMetadata())); +// CHECK-NEXT: _impl::swift_interop_returnDirect_Generics_[[PTRPTRENC]](result, _impl::$s8Generics11GenericPairVyACyxq_Gx_Siq_tcfC(swift::_impl::getOpaquePointer(consumedParamCopy_x), i, swift::_impl::getOpaquePointer(consumedParamCopy_y), swift::TypeMetadataTrait::getTypeMetadata(), swift::TypeMetadataTrait::getTypeMetadata())); // CHECK: SWIFT_INLINE_THUNK T_1_0 GenericPair::genericMethod(const T_1_0& x, const T_0_1& y) const { // CHECK: _impl::$s8Generics11GenericPairV13genericMethodyqd__qd___q_tlF(reinterpret_cast(&returnValue), swift::_impl::getOpaquePointer(x), swift::_impl::getOpaquePointer(y), _impl::swift_interop_passDirect_Generics_[[PTRPTRENC]](_getOpaquePointer()), swift::TypeMetadataTrait::getTypeMetadata(), swift::TypeMetadataTrait::getTypeMetadata(), swift::TypeMetadataTrait::getTypeMetadata()); diff --git a/test/Interop/SwiftToCxx/ownership/consuming-parameter-in-cxx-execution.cpp b/test/Interop/SwiftToCxx/ownership/consuming-parameter-in-cxx-execution.cpp new file mode 100644 index 0000000000000..c2c61bc705a29 --- /dev/null +++ b/test/Interop/SwiftToCxx/ownership/consuming-parameter-in-cxx-execution.cpp @@ -0,0 +1,71 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend %S/consuming-parameter-in-cxx.swift -typecheck -module-name Init -clang-header-expose-decls=all-public -emit-clang-header-path %t/consuming.h + +// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-consume-execution.o +// RUN: %target-interop-build-swift %S/consuming-parameter-in-cxx.swift -o %t/swift-consume-execution -Xlinker %t/swift-consume-execution.o -module-name Init -Xfrontend -entry-point-function-name -Xfrontend swiftMain + +// RUN: %target-codesign %t/swift-consume-execution +// RUN: %target-run %t/swift-consume-execution | %FileCheck %s + +// REQUIRES: executable_test + +#include +#include +#include + +size_t allocCount = 0; +size_t totalAllocs = 0; + +void * _Nonnull trackedAlloc(size_t size, size_t align) { + ++allocCount; + ++totalAllocs; + return malloc(size); +} +void trackedFree(void *_Nonnull p) { + --allocCount; + free(p); +} + +#define SWIFT_CXX_INTEROPERABILITY_OVERRIDE_OPAQUE_STORAGE_alloc trackedAlloc +#define SWIFT_CXX_INTEROPERABILITY_OVERRIDE_OPAQUE_STORAGE_free trackedFree + +#include "consuming.h" + +extern "C" size_t swift_retainCount(void * _Nonnull obj); + +size_t getRetainCount(const Init::AKlass & swiftClass) { + void *p = swift::_impl::_impl_RefCountedClass::getOpaquePointer(swiftClass); + return swift_retainCount(p); +} + +int main() { + using namespace Init; + + { + auto k = AKlass::init(); + k.takeKlass(); + assert(getRetainCount(k) == 1); + } +// CHECK: destroy AKlass + { + auto k = AKlass::init(); + auto x = createSmallStructNonTrivial(k); + auto x2 = InitFromSmall::init(x); + assert(getRetainCount(k) == 2); + } +// CHECK-NEXT: destroy AKlass + { + auto k = AKlass::init(); + auto x = createSmallStructNonTrivial(k); + auto c = TheGenericContainer::init(x); + assert(getRetainCount(k) == 3); + c.takeGenericContainer(); + assert(getRetainCount(k) == 3); + } +// CHECK-NEXT: destroy AKlass + // verify that all of the opaque buffers are freed. + assert(allocCount == 0); + assert(totalAllocs != 0); + return 0; +} diff --git a/test/Interop/SwiftToCxx/ownership/consuming-parameter-in-cxx.swift b/test/Interop/SwiftToCxx/ownership/consuming-parameter-in-cxx.swift new file mode 100644 index 0000000000000..ec379e42a3284 --- /dev/null +++ b/test/Interop/SwiftToCxx/ownership/consuming-parameter-in-cxx.swift @@ -0,0 +1,175 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend %s -typecheck -module-name Init -clang-header-expose-decls=all-public -emit-clang-header-path %t/inits.h +// RUN: %FileCheck --check-prefixes=CHECK,CHECK-NON_EVO %s < %t/inits.h +// RUN: %check-interop-cxx-header-in-clang(%t/inits.h) + +// RUN: %target-swift-frontend %s -typecheck -module-name Init -clang-header-expose-decls=all-public -emit-clang-header-path %t/inits-evo.h -enable-library-evolution +// RUN: %FileCheck %s < %t/inits-evo.h +// RUN: %check-interop-cxx-header-in-clang(%t/inits-evo.h) + +public final class AKlass { + public init() {} + deinit { + print("destroy AKlass") + } + consuming public func takeKlass() {} +} + +public struct SmallStruct { + public let x: UInt32 +} + +public struct SmallStructNonTrivial { + public let k: AKlass + public let x: UInt32 +} + +public struct LargeStructNonTrivial { + public let x1, x2, x3, x4, x5, x6: Int + public let k: AKlass + + consuming public func takeMe() {} +} + +public func createSmallStructNonTrivial(_ k: AKlass) -> SmallStructNonTrivial { + return SmallStructNonTrivial(k: k, x: 0) +} + +public enum EnumNonTrivial { + case a(Int) + case b(AKlass) +} + +public struct InitFromSmall { + public init(_ x : SmallStructNonTrivial) { + self.x = 0 + } + + public func takeSmall(_ x: consuming SmallStruct) { + } + public func takeSmallLarge(_: consuming SmallStructNonTrivial, + _: consuming LargeStructNonTrivial) { + } + + let x: Int +} + +public struct InitFromLargeStructNonTrivial { + public init(_ x : LargeStructNonTrivial) { + self.x = 0 + } + + let x: Int +} + +public struct InitFromKlass { + public init(_ x : AKlass) { + self.x = 0 + } + + let x: Int +} + +public struct InitFromEnumNonTrivial { + public init(_ x : EnumNonTrivial) { + self.x = 0 + } + + let x: Int +} + +public struct TheGenericContainer { + public init(_ x : T) { self.x = x } + + consuming public func takeGenericContainer() {} + + let x: T +} + +public struct TheGenericContainerInitTriv { + public init(_ x : TheGenericContainer) { + self.x = 0 + } + + let x: Int +} + +public struct TheGenericContainerInitNonTriv { + public init(_ x : TheGenericContainer) { + self.x = 0 + } + + let x: Int +} + +// CHECK: SWIFT_INLINE_THUNK void AKlass::takeKlass() { +// CHECK-NEXT: alignas(alignof(AKlass)) char copyBuffer_consumedParamCopy_this[sizeof(AKlass)]; +// CHECK-NEXT: auto &consumedParamCopy_this = *(new(copyBuffer_consumedParamCopy_this) AKlass(*this)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_this(consumedParamCopy_this); +// CHECK-NEXT: return _impl::$s4Init6AKlassC9takeKlassyyF(::swift::_impl::_impl_RefCountedClass::getOpaquePointer(consumedParamCopy_this)); + +// CHECK: SWIFT_INLINE_THUNK InitFromEnumNonTrivial InitFromEnumNonTrivial::init(const EnumNonTrivial& x) { +// CHECK-NEXT: alignas(alignof(EnumNonTrivial)) char copyBuffer_consumedParamCopy_x[sizeof(EnumNonTrivial)]; +// CHECK-NEXT: auto &consumedParamCopy_x = *(new(copyBuffer_consumedParamCopy_x) EnumNonTrivial(x)); +// CHECK-NEXT: ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_x(consumedParamCopy_x); +// CHECK-NEXT: returnNewValue +// CHECK-NEXT: _impl::_impl_EnumNonTrivial::getOpaquePointer(consumedParamCopy_x) + +// CHECK: SWIFT_INLINE_THUNK InitFromKlass InitFromKlass::init(const AKlass& x) { +// CHECK-NEXT: alignas(alignof(AKlass)) char copyBuffer_consumedParamCopy_x[sizeof(AKlass)]; +// CHECK-NEXT: auto &consumedParamCopy_x = *(new(copyBuffer_consumedParamCopy_x) AKlass(x)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_x(consumedParamCopy_x); +// CHECK-NEXT: returnNewValue +// CHECK-NEXT: swift::_impl::_impl_RefCountedClass::getOpaquePointer(consumedParamCopy_x) + +// CHECK: SWIFT_INLINE_THUNK InitFromLargeStructNonTrivial InitFromLargeStructNonTrivial::init(const LargeStructNonTrivial& x) { +// CHECK-NEXT: alignas(alignof(LargeStructNonTrivial)) char copyBuffer_consumedParamCopy_x[sizeof(LargeStructNonTrivial)]; +// CHECK-NEXT: auto &consumedParamCopy_x = *(new(copyBuffer_consumedParamCopy_x) LargeStructNonTrivial(x)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_x(consumedParamCopy_x); + +// CHECK: SWIFT_INLINE_THUNK InitFromSmall InitFromSmall::init(const SmallStructNonTrivial& x) { +// CHECK-NEXT: alignas(alignof(SmallStructNonTrivial)) char copyBuffer_consumedParamCopy_x[sizeof(SmallStructNonTrivial)]; +// CHECK-NEXT: auto &consumedParamCopy_x = *(new(copyBuffer_consumedParamCopy_x) SmallStructNonTrivial(x)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_x(consumedParamCopy_x); + +// CHECK: SWIFT_INLINE_THUNK void InitFromSmall::takeSmallLarge(const SmallStructNonTrivial& _1, const LargeStructNonTrivial& _2) const { +// CHECK-NEXT: alignas(alignof(SmallStructNonTrivial)) char copyBuffer_consumedParamCopy_1[sizeof(SmallStructNonTrivial)]; +// CHECK-NEXT: auto &consumedParamCopy_1 = *(new(copyBuffer_consumedParamCopy_1) SmallStructNonTrivial(_1)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_1(consumedParamCopy_1); +// CHECK-NEXT: alignas(alignof(LargeStructNonTrivial)) char copyBuffer_consumedParamCopy_2[sizeof(LargeStructNonTrivial)]; +// CHECK-NEXT: auto &consumedParamCopy_2 = *(new(copyBuffer_consumedParamCopy_2) LargeStructNonTrivial(_2)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_2(consumedParamCopy_2); +// CHECK-NON_EVO-NEXT: return _impl::$s4Init0A9FromSmallV04takeC5LargeyyAA0C16StructNonTrivialVn_AA0efgH0VntF(_impl::swift_interop_passDirect_Init_void_ptr_0_8_uint32_t_8_12(_impl::_impl_SmallStructNonTrivial::getOpaquePointer(consumedParamCopy_1)), _impl::_impl_LargeStructNonTrivial::getOpaquePointer(consumedParamCopy_2), _impl::swift_interop_passDirect_Init_uint64_t_0_8(_getOpaquePointer())); + +// CHECK: SWIFT_INLINE_THUNK void LargeStructNonTrivial::takeMe() const { +// CHECK-NEXT: alignas(alignof(LargeStructNonTrivial)) char copyBuffer_consumedParamCopy_this[sizeof(LargeStructNonTrivial)]; +// CHECK-NEXT: auto &consumedParamCopy_this = *(new(copyBuffer_consumedParamCopy_this) LargeStructNonTrivial(*this)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_this(consumedParamCopy_this); +// CHECK-NEXT: return _impl::$s4Init21LargeStructNonTrivialV6takeMeyyF(_impl::_impl_LargeStructNonTrivial::getOpaquePointer(consumedParamCopy_this)); + +// CHECK: SWIFT_INLINE_THUNK TheGenericContainer TheGenericContainer::init(const T_0_0& x) { +//CHECK-NEXT:#ifndef __cpp_concepts +//CHECK-NEXT: static_assert +//CHECK-NEXT:#endif // __cpp_concepts +//CHECK-NEXT: alignas(alignof(T_0_0)) char copyBuffer_consumedParamCopy_x[sizeof(T_0_0)]; +//CHECK-NEXT: auto &consumedParamCopy_x = *(new(copyBuffer_consumedParamCopy_x) T_0_0(x)); +//CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer storageGuard_consumedParamCopy_x(consumedParamCopy_x); +//CHECK-NEXT: returnNewValue +//CHECK-NEXT: swift::_impl::getOpaquePointer(consumedParamCopy_x) + +// CHECK: SWIFT_INLINE_THUNK void TheGenericContainer::takeGenericContainer() const { +// CHECK-NEXT: #ifndef __cpp_concepts +// CHECK-NEXT: static_assert +// CHECK-NEXT: #endif // __cpp_concepts +// CHECK-NEXT: alignas(alignof(TheGenericContainer)) char copyBuffer_consumedParamCopy_this[sizeof(TheGenericContainer)]; +// CHECK-NEXT: auto &consumedParamCopy_this = *(new(copyBuffer_consumedParamCopy_this) TheGenericContainer(*this)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer> storageGuard_consumedParamCopy_this(consumedParamCopy_this); +// CHECK-NEXT: return _impl::$s4Init19TheGenericContainerV04takecD0yyF(swift::TypeMetadataTrait>::getTypeMetadata(), _impl::_impl_TheGenericContainer::getOpaquePointer(consumedParamCopy_this)); + +// CHECK: SWIFT_INLINE_THUNK TheGenericContainerInitNonTriv TheGenericContainerInitNonTriv::init(const TheGenericContainer& x) { +// CHECK-NEXT: alignas(alignof(TheGenericContainer)) char copyBuffer_consumedParamCopy_x[sizeof(TheGenericContainer)]; +// CHECK-NEXT: auto &consumedParamCopy_x = *(new(copyBuffer_consumedParamCopy_x) TheGenericContainer(x)); +// CHECK-NEXT: swift::_impl::ConsumedValueStorageDestroyer> storageGuard_consumedParamCopy_x(consumedParamCopy_x); + +// CHECK: SWIFT_INLINE_THUNK TheGenericContainerInitTriv TheGenericContainerInitTriv::init(const TheGenericContainer& x) { +// CHECK-NON_EVO-NEXT: return diff --git a/test/Interop/SwiftToCxx/ownership/resilient-consuming-parameter-in-cxx-execution.cpp b/test/Interop/SwiftToCxx/ownership/resilient-consuming-parameter-in-cxx-execution.cpp new file mode 100644 index 0000000000000..c8eb9fde47d2e --- /dev/null +++ b/test/Interop/SwiftToCxx/ownership/resilient-consuming-parameter-in-cxx-execution.cpp @@ -0,0 +1,11 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend %S/consuming-parameter-in-cxx.swift -typecheck -module-name Init -clang-header-expose-decls=all-public -emit-clang-header-path %t/consuming.h -enable-library-evolution + +// RUN: %target-interop-build-clangxx -c %S/consuming-parameter-in-cxx-execution.cpp -I %t -o %t/swift-consume-execution.o +// RUN: %target-interop-build-swift %S/consuming-parameter-in-cxx.swift -o %t/swift-consume-execution-evo -Xlinker %t/swift-consume-execution.o -module-name Init -Xfrontend -entry-point-function-name -Xfrontend swiftMain -enable-library-evolution + +// RUN: %target-codesign %t/swift-consume-execution-evo +// RUN: %target-run %t/swift-consume-execution-evo | %FileCheck %S/consuming-parameter-in-cxx-execution.cpp + +// REQUIRES: executable_test diff --git a/test/Interop/SwiftToCxx/stdlib/array/array-execution.cpp b/test/Interop/SwiftToCxx/stdlib/array/array-execution.cpp index 67ed7e35d96f3..4510735d80e56 100644 --- a/test/Interop/SwiftToCxx/stdlib/array/array-execution.cpp +++ b/test/Interop/SwiftToCxx/stdlib/array/array-execution.cpp @@ -26,6 +26,13 @@ public func printArray(_ val: Array) { print(val) } +public func printStrings(_ strings: [String]) { + for s in strings { + print("GOT STRING '\(s)'") + } + print("DONE PRINTING.") +} + //--- array-execution.cpp #include @@ -33,7 +40,6 @@ public func printArray(_ val: Array) { int main() { using namespace swift; - { Array val = UseArray::createArray(2); UseArray::printArray(UseArray::passthroughArray(val)); @@ -60,5 +66,12 @@ int main() { } // CHECK-NEXT: [-11] // CHECK-NEXT: [] + { + auto array = swift::Array::init(); + array.append("123456789ABCDEFG"); + UseArray::printStrings(array); + } +// CHECK-NEXT: GOT STRING '123456789ABCDEFG' +// CHECK-NEXT: DONE PRINTING return 0; } diff --git a/test/Interop/SwiftToCxx/stdlib/combination-of-stdlib-generics-in-cxx.swift b/test/Interop/SwiftToCxx/stdlib/combination-of-stdlib-generics-in-cxx.swift new file mode 100644 index 0000000000000..e5709a7634847 --- /dev/null +++ b/test/Interop/SwiftToCxx/stdlib/combination-of-stdlib-generics-in-cxx.swift @@ -0,0 +1,13 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend -typecheck %s -typecheck -module-name UseOptional -enable-experimental-cxx-interop -emit-clang-header-path %t/stdlib.h +// RUN: %FileCheck %s < %t/stdlib.h + +// RUN: %check-interop-cxx-header-in-clang(-DSWIFT_CXX_INTEROP_HIDE_STL_OVERLAY %t/stdlib.h -Wno-unused-private-field -Wno-unused-function) + +@_expose(Cxx) +public func testOptIntArray() -> [Int]? { + return [] +} + +// CHECK: SWIFT_INLINE_THUNK swift::Optional> testOptIntArray() diff --git a/test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift b/test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift index 17a2cb30e33ff..fb6eac405412a 100644 --- a/test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift +++ b/test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift @@ -22,6 +22,7 @@ // CHECK-NEXT: class SWIFT_SYMBOL("s:Sa") Array; // CHECK: template // CHECK: template +// CHECK: template // CHECK-NEXT: #ifdef __cpp_concepts // CHECK-NEXT: requires swift::isUsableInGenericContext // CHECK-NEXT: #endif @@ -41,6 +42,7 @@ // CHECK: SWIFT_INLINE_THUNK swift::Int getCount() const SWIFT_SYMBOL({{.*}}); // CHECK: SWIFT_INLINE_THUNK swift::Int getCapacity() const SWIFT_SYMBOL({{.*}}); +// CHECK: template // CHECK: template // CHECK: template