diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index b852ec28041dc..25f2fb25f6cfc 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2472,39 +2472,33 @@ namespace { } if (cxxRecordDecl) { - // FIXME: Swift right now uses AddressOnly type layout - // in a way that conflates C++ types - // that need to be destroyed or copied explicitly with C++ - // types that have to be passed indirectly, because - // only AddressOnly types can be copied or destroyed using C++ - // semantics. However, in actuality these two concepts are - // separate and don't map to one notion of AddressOnly type - // layout cleanly. We should reserve the use of AddressOnly - // type layout when types have to use C++ copy/move/destroy - // operations, but allow AddressOnly types to be passed - // directly as well. This will help unify the MSVC and - // Itanium difference here, and will allow us to support - // trivial_abi C++ types as well. - auto isNonTrivialForPurposeOfCalls = - [](const clang::CXXRecordDecl *decl) -> bool { - return decl->hasNonTrivialCopyConstructor() || - decl->hasNonTrivialMoveConstructor() || - !decl->hasTrivialDestructor(); - }; - auto isAddressOnlySwiftStruct = - [&](const clang::CXXRecordDecl *decl) -> bool { - // MSVC ABI allows non-trivially destroyed C++ types - // to be passed in register. This is not supported, as such - // type wouldn't be destroyed in Swift correctly. Therefore, - // force AddressOnly type layout using the old heuristic. - // FIXME: Support can pass in registers for MSVC correctly. - if (Impl.SwiftContext.LangOpts.Target.isWindowsMSVCEnvironment()) - return isNonTrivialForPurposeOfCalls(decl); - return !decl->canPassInRegisters(); - }; - if (auto structResult = dyn_cast(result)) - structResult->setIsCxxNonTrivial( - isAddressOnlySwiftStruct(cxxRecordDecl)); + if (auto structResult = dyn_cast(result)) { + // Address-only type is a type that can't be passed in registers. + // Address-only types are typically non-trivial, however some + // non-trivial types can be loadable as well (although such types + // are not yet available in Swift). + bool isAddressOnly = !cxxRecordDecl->canPassInRegisters(); + // Check if the given type is non-trivial to ensure we can + // still perform the right copy/move/destroy even if it's + // not an address-only type. + auto isNonTrivial = [](const clang::CXXRecordDecl *decl) -> bool { + return decl->hasNonTrivialCopyConstructor() || + decl->hasNonTrivialMoveConstructor() || + !decl->hasTrivialDestructor(); + }; + if (!isAddressOnly && + Impl.SwiftContext.LangOpts.Target.isWindowsMSVCEnvironment() && + isNonTrivial(cxxRecordDecl)) { + // MSVC ABI allows non-trivially destroyed C++ types + // to be passed in register. This is not supported, as such + // type wouldn't be destroyed in Swift correctly. Therefore, + // mark this type as unavailable. + // FIXME: Support can pass in registers for MSVC correctly. + Impl.markUnavailable(result, "non-trivial C++ class with trivial " + "ABI is not yet available in Swift"); + } + structResult->setIsCxxNonTrivial(isAddressOnly); + } for (auto &getterAndSetter : Impl.GetterSetterMap[result]) { auto getter = getterAndSetter.second.first; diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 7ed01da31ec83..a61d57a887053 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -2301,7 +2301,14 @@ class SyncCallEmission final : public CallEmission { SILFunctionConventions fnConv(origCalleeType, IGF.getSILModule()); // Pass along the indirect result pointers. - original.transferInto(adjusted, fnConv.getNumIndirectSILResults()); + auto passIndirectResults = [&]() { + original.transferInto(adjusted, fnConv.getNumIndirectSILResults()); + }; + // Indirect results for C++ methods can come + // after `this`. + if (getCallee().getRepresentation() != + SILFunctionTypeRepresentation::CXXMethod) + passIndirectResults(); // Pass along the coroutine buffer. switch (origCalleeType->getCoroutineKind()) { @@ -2341,7 +2348,14 @@ class SyncCallEmission final : public CallEmission { IGF.IGM.getPointerAlignment()); } + // Windows ABI places `this` before the + // returned indirect values. + bool isThisFirst = IGF.IGM.Triple.isWindowsMSVCEnvironment(); + if (!isThisFirst) + passIndirectResults(); adjusted.add(arg); + if (isThisFirst) + passIndirectResults(); } LLVM_FALLTHROUGH; diff --git a/test/Interop/Cxx/class/Inputs/destructors.h b/test/Interop/Cxx/class/Inputs/destructors.h index 54245147a0ca5..d61f14cb9e91a 100644 --- a/test/Interop/Cxx/class/Inputs/destructors.h +++ b/test/Interop/Cxx/class/Inputs/destructors.h @@ -6,11 +6,21 @@ struct DummyStruct {}; struct __attribute__((swift_attr("import_unsafe"))) HasUserProvidedDestructorAndDummy { DummyStruct dummy; + HasUserProvidedDestructorAndDummy(DummyStruct dummy) : dummy(dummy) {} +#if __is_target_os(windows) + // On windows, force this type to be address-only. + HasUserProvidedDestructorAndDummy(const HasUserProvidedDestructorAndDummy &) {} +#endif ~HasUserProvidedDestructorAndDummy() {} }; struct __attribute__((swift_attr("import_unsafe"))) HasUserProvidedDestructor { int *value; +#if __is_target_os(windows) + // On windows, force this type to be address-only. + HasUserProvidedDestructor() {} + HasUserProvidedDestructor(const HasUserProvidedDestructor &other) {} +#endif ~HasUserProvidedDestructor() { *value = 42; } }; diff --git a/test/Interop/Cxx/class/Inputs/nodiscard.h b/test/Interop/Cxx/class/Inputs/nodiscard.h index 3d82c1dff2865..e66b487b004cc 100644 --- a/test/Interop/Cxx/class/Inputs/nodiscard.h +++ b/test/Interop/Cxx/class/Inputs/nodiscard.h @@ -6,6 +6,7 @@ class NoDiscardMultiply { public: NoDiscardMultiply() {} + NoDiscardMultiply(const NoDiscardMultiply &) { } ~NoDiscardMultiply() {} [[nodiscard]] int Multiply(int x, int y) { return x * y; } diff --git a/test/Interop/Cxx/class/Inputs/protocol-conformance.h b/test/Interop/Cxx/class/Inputs/protocol-conformance.h index d0452c90112a7..b6f2f5a995540 100644 --- a/test/Interop/Cxx/class/Inputs/protocol-conformance.h +++ b/test/Interop/Cxx/class/Inputs/protocol-conformance.h @@ -12,6 +12,7 @@ struct DoesNotConformToProtocol { struct DummyStruct {}; struct __attribute__((swift_attr("import_unsafe"))) NonTrivial { + NonTrivial(const NonTrivial &other) {} ~NonTrivial() {} NonTrivial(DummyStruct) {} NonTrivial() {} @@ -67,4 +68,4 @@ struct HasOperatorPlusEqual { using HasOperatorPlusEqualInt = HasOperatorPlusEqual; -#endif // TEST_INTEROP_CXX_CLASS_INPUTS_PROTOCOL_CONFORMANCE_H \ No newline at end of file +#endif // TEST_INTEROP_CXX_CLASS_INPUTS_PROTOCOL_CONFORMANCE_H diff --git a/test/Interop/Cxx/class/Inputs/type-classification.h b/test/Interop/Cxx/class/Inputs/type-classification.h index 919f66e1d1fe1..0664cf0230d5b 100644 --- a/test/Interop/Cxx/class/Inputs/type-classification.h +++ b/test/Interop/Cxx/class/Inputs/type-classification.h @@ -80,6 +80,12 @@ struct StructWithSubobjectMoveAssignment { }; struct __attribute__((swift_attr("import_unsafe"))) StructWithDestructor { +#if __is_target_os(windows) + // On windows, force this type to be address-only. + StructWithDestructor() {} + StructWithDestructor(const StructWithDestructor &other) {} +#endif + ~StructWithDestructor() {} }; diff --git a/test/Interop/Cxx/class/delete-operator-destructor-ref-irgen.swift b/test/Interop/Cxx/class/delete-operator-destructor-ref-irgen.swift index 312b23de51edf..f2e4b5e6023d3 100644 --- a/test/Interop/Cxx/class/delete-operator-destructor-ref-irgen.swift +++ b/test/Interop/Cxx/class/delete-operator-destructor-ref-irgen.swift @@ -24,6 +24,7 @@ public: class Container { public: Container() : pointer(new BaseClass) {} + Container(const Container &other) : pointer(new BaseClass) {} ~Container() { delete pointer; } inline int method() const { diff --git a/test/Interop/Cxx/class/destructors-correct-abi-irgen.swift b/test/Interop/Cxx/class/destructors-correct-abi-irgen.swift index 4129f02020ab7..e27954bb76d21 100644 --- a/test/Interop/Cxx/class/destructors-correct-abi-irgen.swift +++ b/test/Interop/Cxx/class/destructors-correct-abi-irgen.swift @@ -4,10 +4,12 @@ import Destructors // CHECK-LABEL: define {{.*}}void @"$s4main4testyyF" // CHECK: [[H:%.*]] = alloca %TSo33HasUserProvidedDestructorAndDummyV +// CHECK: [[CXX_THIS_PRE:%.*]] = bitcast %TSo33HasUserProvidedDestructorAndDummyV* [[H]] to %struct.HasUserProvidedDestructorAndDummy* // CHECK: [[CXX_THIS:%.*]] = bitcast %TSo33HasUserProvidedDestructorAndDummyV* [[H]] to %struct.HasUserProvidedDestructorAndDummy* // CHECK: call {{.*}}@{{_ZN33HasUserProvidedDestructorAndDummyD(1|2)Ev|"\?\?1HasUserProvidedDestructorAndDummy@@QEAA@XZ"}}(%struct.HasUserProvidedDestructorAndDummy* [[CXX_THIS]]) + // CHECK: ret void public func test() { let d = DummyStruct() - let h = HasUserProvidedDestructorAndDummy(dummy: d) + let h = HasUserProvidedDestructorAndDummy(d) } diff --git a/test/Interop/Cxx/class/inheritance/Inputs/fields.h b/test/Interop/Cxx/class/inheritance/Inputs/fields.h index 1159eb5d9d8ae..5796d9db06b38 100644 --- a/test/Interop/Cxx/class/inheritance/Inputs/fields.h +++ b/test/Interop/Cxx/class/inheritance/Inputs/fields.h @@ -30,6 +30,7 @@ struct DerivedFromOneField : OneField {}; struct __attribute__((swift_attr("import_unsafe"))) NonTrivial { NonTrivial() {} + NonTrivial(const NonTrivial &) {} ~NonTrivial() {} }; @@ -45,6 +46,7 @@ struct NonTrivialDerivedWithOneField : NonTrivialHasThreeFields { struct __attribute__((swift_attr("import_unsafe"))) NonTrivialHasOneField { NonTrivialHasOneField() {} + NonTrivialHasOneField(const NonTrivialHasOneField &other) : e(other.e) {} ~NonTrivialHasOneField() {} int e = 5; diff --git a/test/Interop/Cxx/class/inheritance/Inputs/functions.h b/test/Interop/Cxx/class/inheritance/Inputs/functions.h index 0df29723e3b4e..6075cf124c800 100644 --- a/test/Interop/Cxx/class/inheritance/Inputs/functions.h +++ b/test/Interop/Cxx/class/inheritance/Inputs/functions.h @@ -1,5 +1,6 @@ struct __attribute__((swift_attr("import_unsafe"))) NonTrivial { NonTrivial() {} + NonTrivial(const NonTrivial &) {} ~NonTrivial() {} inline const char *inNonTrivial() const diff --git a/test/Interop/Cxx/class/method/Inputs/methods.h b/test/Interop/Cxx/class/method/Inputs/methods.h index 5d75a8ace7fbe..776a67627fc7e 100644 --- a/test/Interop/Cxx/class/method/Inputs/methods.h +++ b/test/Interop/Cxx/class/method/Inputs/methods.h @@ -4,6 +4,11 @@ struct __attribute__((swift_attr("import_unsafe"))) NonTrivialInWrapper { int value; + NonTrivialInWrapper(int value) : value(value) {} + + // explicit copy constructor is needed, as on Windows a destructor + // still makes this a type that's passed in registers. + NonTrivialInWrapper(const NonTrivialInWrapper &other) : value(other.value) {} ~NonTrivialInWrapper() { } }; diff --git a/test/Interop/Cxx/class/method/methods-this-and-indirect-return-irgen-itanium.swift b/test/Interop/Cxx/class/method/methods-this-and-indirect-return-irgen-itanium.swift new file mode 100644 index 0000000000000..6da16568a873c --- /dev/null +++ b/test/Interop/Cxx/class/method/methods-this-and-indirect-return-irgen-itanium.swift @@ -0,0 +1,19 @@ +// RUN: %target-swift-emit-irgen -I %S/Inputs -enable-experimental-cxx-interop %s -Xcc -fignore-exceptions | %FileCheck %s + +// UNSUPPORTED: OS=windows-msvc + +import Methods + +public func use() -> CInt { + var instance = HasMethods() + let result = instance.nonConstPassThroughAsWrapper(42) + return result.value +} + +// CHECK: %[[instance:.*]] = alloca %TSo10HasMethodsV +// CHECK: %[[result:.*]] = alloca %TSo19NonTrivialInWrapperV +// CHECK: %[[CXX_THIS_PRE:.*]] = bitcast %TSo10HasMethodsV* %[[instance]] to %struct.HasMethods* +// CHECK: %[[CXX_THIS:.*]] = bitcast %TSo10HasMethodsV* %[[instance]] to %struct.HasMethods* +// CHECK: call void @_ZN10HasMethods28nonConstPassThroughAsWrapperEi(%struct.NonTrivialInWrapper* sret(%struct.NonTrivialInWrapper) %{{.*}}, %struct.HasMethods* %[[CXX_THIS]], i32 42) + +// CHECK: define {{.*}} void @_ZN10HasMethods28nonConstPassThroughAsWrapperEi(%struct.NonTrivialInWrapper* noalias sret(%struct.NonTrivialInWrapper) {{.*}} %{{.*}}, %struct.HasMethods* {{.*}} %{{.*}}, i32 noundef %{{.*}}) diff --git a/test/Interop/Cxx/class/method/methods-this-and-indirect-return-irgen-msvc.swift b/test/Interop/Cxx/class/method/methods-this-and-indirect-return-irgen-msvc.swift new file mode 100644 index 0000000000000..f49892034875d --- /dev/null +++ b/test/Interop/Cxx/class/method/methods-this-and-indirect-return-irgen-msvc.swift @@ -0,0 +1,19 @@ +// RUN: %target-swift-emit-irgen -I %S/Inputs -enable-experimental-cxx-interop %s | %FileCheck %s + +// REQUIRES: OS=windows-msvc + +import Methods + +public func use() -> CInt { + var instance = HasMethods() + let result = instance.nonConstPassThroughAsWrapper(42) + return result.value +} + +// CHECK: %[[instance:.*]] = alloca %TSo10HasMethodsV +// CHECK: %[[result:.*]] = alloca %TSo19NonTrivialInWrapperV +// CHECK: %[[CXX_THIS_PRE:.*]] = bitcast %TSo10HasMethodsV* %[[instance]] to %struct.HasMethods* +// CHECK: %[[CXX_THIS:.*]] = bitcast %TSo10HasMethodsV* %[[instance]] to %struct.HasMethods* +// CHECK: call void @"?nonConstPassThroughAsWrapper@HasMethods@@QEAA?AUNonTrivialInWrapper@@H@Z"(%struct.HasMethods* %[[CXX_THIS]], %struct.NonTrivialInWrapper* sret(%struct.NonTrivialInWrapper) %{{.*}}, i32 42) + +// CHECK: define {{.*}} void @"?nonConstPassThroughAsWrapper@HasMethods@@QEAA?AUNonTrivialInWrapper@@H@Z"(%struct.HasMethods* {{.*}} %{{.*}}, %struct.NonTrivialInWrapper* noalias sret(%struct.NonTrivialInWrapper) {{.*}} %{{.*}}, i32 noundef %{{.*}}) diff --git a/test/Interop/Cxx/class/method/methods.swift b/test/Interop/Cxx/class/method/methods.swift index f5febb45f86ef..b867fd00c0f22 100644 --- a/test/Interop/Cxx/class/method/methods.swift +++ b/test/Interop/Cxx/class/method/methods.swift @@ -1,9 +1,6 @@ // RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -enable-experimental-cxx-interop) // // REQUIRES: executable_test -// -// Crash when running on windows: rdar://88391102 -// XFAIL: OS=windows-msvc import StdlibUnittest import Methods @@ -34,15 +31,15 @@ CxxMethodTestSuite.test("(Int, Int) -> Int") { CxxMethodTestSuite.test("(NonTrivialInWrapper, NonTrivialInWrapper) -> Int") { var instance = HasMethods() - expectEqual(42, instance.nonConstSum(NonTrivialInWrapper(value: 40), NonTrivialInWrapper(value: 2))) - expectEqual(42, instance.constSum(NonTrivialInWrapper(value: 40), NonTrivialInWrapper(value: 2))) + expectEqual(42, instance.nonConstSum(NonTrivialInWrapper(40), NonTrivialInWrapper(2))) + expectEqual(42, instance.constSum(NonTrivialInWrapper(40), NonTrivialInWrapper(2))) } CxxMethodTestSuite.test("(NonTrivialInWrapper, NonTrivialInWrapper) -> NonTrivialInWrapper") { var instance = HasMethods() - expectEqual(42, instance.nonConstSumAsWrapper(NonTrivialInWrapper(value: 40), NonTrivialInWrapper(value: 2)).value) - expectEqual(42, instance.constSumAsWrapper(NonTrivialInWrapper(value: 40), NonTrivialInWrapper(value: 2)).value) + expectEqual(42, instance.nonConstSumAsWrapper(NonTrivialInWrapper(40), NonTrivialInWrapper(2)).value) + expectEqual(42, instance.constSumAsWrapper(NonTrivialInWrapper(40), NonTrivialInWrapper(2)).value) } CxxMethodTestSuite.test("(Int) -> NonTrivialInWrapper") { diff --git a/test/Interop/Cxx/exceptions/trap-on-exception-irgen-itanium.swift b/test/Interop/Cxx/exceptions/trap-on-exception-irgen-itanium.swift index 19a2f24d8b26d..8e1d1291c93af 100644 --- a/test/Interop/Cxx/exceptions/trap-on-exception-irgen-itanium.swift +++ b/test/Interop/Cxx/exceptions/trap-on-exception-irgen-itanium.swift @@ -92,6 +92,11 @@ public: class ClassWithDestructor { int m = 0; public: +#if __is_target_os(windows) + // On windows, force this type to be address-only. + inline ClassWithDestructor() noexcept {} + inline ClassWithDestructor(const ClassWithDestructor &other) noexcept : m(other.m) {} +#endif inline ~ClassWithDestructor() { (void)freeFunctionNoThrow(0); } @@ -100,6 +105,11 @@ public: class ClassWithThrowingDestructor { int m = 0; public: +#if __is_target_os(windows) + // On windows, force this type to be address-only. + inline ClassWithThrowingDestructor() noexcept {} + inline ClassWithThrowingDestructor(const ClassWithThrowingDestructor &other) noexcept : m(other.m) {} +#endif inline ~ClassWithThrowingDestructor() noexcept(false) { throw 2; } @@ -139,6 +149,8 @@ struct StructWithDefaultConstructor { struct NonTrivial { + NonTrivial() noexcept; + NonTrivial(const NonTrivial &other) noexcept; ~NonTrivial() {} }; diff --git a/test/Interop/Cxx/templates/member-templates-silgen.swift b/test/Interop/Cxx/templates/member-templates-silgen.swift index 3a25f0f2b21a4..c53c44fe3e35d 100644 --- a/test/Interop/Cxx/templates/member-templates-silgen.swift +++ b/test/Interop/Cxx/templates/member-templates-silgen.swift @@ -1,23 +1,19 @@ // RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-experimental-cxx-interop | %FileCheck %s -// We can't yet call member functions correctly on Windows -// (https://github.com/apple/swift/issues/55575). -// XFAIL: OS=windows-msvc - import MemberTemplates // CHECK-LABEL: sil hidden @$s4main9basicTestyyF : $@convention(thin) () -> () -// CHECK: [[ADD:%.*]] = function_ref @_ZN18HasMemberTemplates17addSameTypeParamsIiEET_S1_S1_ : $@convention(cxx_method) (Int32, Int32, @inout HasMemberTemplates) -> Int32 +// CHECK: [[ADD:%.*]] = function_ref @{{_ZN18HasMemberTemplates17addSameTypeParamsIiEET_S1_S1_|\?\?\$addSameTypeParams@H@HasMemberTemplates@@QEAAHHH@Z}} : $@convention(cxx_method) (Int32, Int32, @inout HasMemberTemplates) -> Int32 // CHECK: apply [[ADD]]({{.*}}) : $@convention(cxx_method) (Int32, Int32, @inout HasMemberTemplates) -> Int32 -// CHECK: [[ADD_TWO_TEMPLATES:%.*]] = function_ref @_ZN18HasMemberTemplates18addMixedTypeParamsIiiEET_S1_T0_ : $@convention(cxx_method) (Int32, Int32, @inout HasMemberTemplates) -> Int32 +// CHECK: [[ADD_TWO_TEMPLATES:%.*]] = function_ref @{{_ZN18HasMemberTemplates18addMixedTypeParamsIiiEET_S1_T0_|\?\?\$addMixedTypeParams@HH@HasMemberTemplates@@QEAAHHH@Z}} : $@convention(cxx_method) (Int32, Int32, @inout HasMemberTemplates) -> Int32 // CHECK: apply [[ADD_TWO_TEMPLATES]]({{.*}}) : $@convention(cxx_method) (Int32, Int32, @inout HasMemberTemplates) -> Int32 -// CHECK: [[ADD_ALL:%.*]] = function_ref @_ZN18HasMemberTemplates6addAllIiiEEiiT_T0_ : $@convention(cxx_method) (Int32, Int32, Int32, @inout HasMemberTemplates) -> Int32 +// CHECK: [[ADD_ALL:%.*]] = function_ref @{{_ZN18HasMemberTemplates6addAllIiiEEiiT_T0_|\?\?\$addAll@HH@HasMemberTemplates@@QEAAHHHH@Z}} : $@convention(cxx_method) (Int32, Int32, Int32, @inout HasMemberTemplates) -> Int32 // CHECK: apply [[ADD_ALL]]({{.*}}) : $@convention(cxx_method) (Int32, Int32, Int32, @inout HasMemberTemplates) -> Int32 -// CHECK: [[DO_NOTHING:%.*]] = function_ref @_ZN18HasMemberTemplates17doNothingConstRefIiEEvRKT_ : $@convention(cxx_method) (@in_guaranteed Int32, @inout HasMemberTemplates) -> () +// CHECK: [[DO_NOTHING:%.*]] = function_ref @{{_ZN18HasMemberTemplates17doNothingConstRefIiEEvRKT_|\?\?\$doNothingConstRef@H@HasMemberTemplates@@QEAAXAEBH@Z}} : $@convention(cxx_method) (@in_guaranteed Int32, @inout HasMemberTemplates) -> () // CHECK: apply [[DO_NOTHING]]({{.*}}) : $@convention(cxx_method) (@in_guaranteed Int32, @inout HasMemberTemplates) -> () // CHECK-LABEL: end sil function '$s4main9basicTestyyF' @@ -30,17 +26,17 @@ func basicTest() { obj.doNothingConstRef(i) } -// CHECK-LABEL: sil [clang HasMemberTemplates.addSameTypeParams] @_ZN18HasMemberTemplates17addSameTypeParamsIiEET_S1_S1_ : $@convention(cxx_method) (Int32, Int32, @inout HasMemberTemplates) -> Int32 +// CHECK-LABEL: sil [clang HasMemberTemplates.addSameTypeParams] @{{_ZN18HasMemberTemplates17addSameTypeParamsIiEET_S1_S1_|\?\?\$addSameTypeParams@H@HasMemberTemplates@@QEAAHHH@Z}} : $@convention(cxx_method) (Int32, Int32, @inout HasMemberTemplates) -> Int32 -// CHECK-LABEL: sil [clang HasMemberTemplates.addMixedTypeParams] @_ZN18HasMemberTemplates18addMixedTypeParamsIiiEET_S1_T0_ : $@convention(cxx_method) (Int32, Int32, @inout HasMemberTemplates) -> Int32 +// CHECK-LABEL: sil [clang HasMemberTemplates.addMixedTypeParams] @{{_ZN18HasMemberTemplates18addMixedTypeParamsIiiEET_S1_T0_|\?\?\$addMixedTypeParams@HH@HasMemberTemplates@@QEAAHHH@Z}} : $@convention(cxx_method) (Int32, Int32, @inout HasMemberTemplates) -> Int32 -// CHECK-LABEL: sil [clang HasMemberTemplates.addAll] @_ZN18HasMemberTemplates6addAllIiiEEiiT_T0_ : $@convention(cxx_method) (Int32, Int32, Int32, @inout HasMemberTemplates) -> Int32 +// CHECK-LABEL: sil [clang HasMemberTemplates.addAll] @{{_ZN18HasMemberTemplates6addAllIiiEEiiT_T0_|\?\?\$addAll@HH@HasMemberTemplates@@QEAAHHHH@Z}} : $@convention(cxx_method) (Int32, Int32, Int32, @inout HasMemberTemplates) -> Int32 -// CHECK-LABEL: sil [clang HasMemberTemplates.doNothingConstRef] @_ZN18HasMemberTemplates17doNothingConstRefIiEEvRKT_ : $@convention(cxx_method) (@in_guaranteed Int32, @inout HasMemberTemplates) -> () +// CHECK-LABEL: sil [clang HasMemberTemplates.doNothingConstRef] @{{_ZN18HasMemberTemplates17doNothingConstRefIiEEvRKT_|\?\?\$doNothingConstRef@H@HasMemberTemplates@@QEAAXAEBH@Z}} : $@convention(cxx_method) (@in_guaranteed Int32, @inout HasMemberTemplates) -> () // CHECK-LABEL: sil hidden @$s4main12testSetValueyyF : $@convention(thin) () -> () -// CHECK: [[SET_VALUE:%.*]] = function_ref @_ZN32TemplateClassWithMemberTemplatesIiE8setValueIlEEvT_ : $@convention(cxx_method) (Int, @inout TemplateClassWithMemberTemplates) -> () +// CHECK: [[SET_VALUE:%.*]] = function_ref @{{_ZN32TemplateClassWithMemberTemplatesIiE8setValueIlEEvT_|\?\?\$setValue@_J@\?\$TemplateClassWithMemberTemplates@H@@QEAAX_J@Z}} : $@convention(cxx_method) (Int, @inout TemplateClassWithMemberTemplates) -> () // CHECK: apply [[SET_VALUE]]({{.*}}) : $@convention(cxx_method) (Int, @inout TemplateClassWithMemberTemplates) -> () // CHECK-LABEL: end sil function '$s4main12testSetValueyyF' @@ -51,13 +47,13 @@ func testSetValue() { // CHECK-LABEL: sil hidden @$s4main17testStaticMembersyyF : $@convention(thin) () -> () -// CHECK: [[ADD_FN:%.*]] = function_ref @_ZN24HasStaticMemberTemplates3addIlEET_S1_S1_ : $@convention(c) (Int, Int) -> Int +// CHECK: [[ADD_FN:%.*]] = function_ref @{{_ZN24HasStaticMemberTemplates3addIlEET_S1_S1_|\?\?\$add@_J@HasStaticMemberTemplates@@SA_J_J0@Z}} : $@convention(c) (Int, Int) -> Int // CHECK: apply [[ADD_FN]]({{.*}}) : $@convention(c) (Int, Int) -> Int -// CHECK: [[ADD_TWO_TEMPLATES_FN:%.*]] = function_ref @_ZN24HasStaticMemberTemplates15addTwoTemplatesIlcEET_S1_T0_ : $@convention(c) (Int, Int8) -> Int +// CHECK: [[ADD_TWO_TEMPLATES_FN:%.*]] = function_ref @{{_ZN24HasStaticMemberTemplates15addTwoTemplatesIlcEET_S1_T0_|\?\?\$addTwoTemplates@_JD@HasStaticMemberTemplates@@SA_J_JD@Z}} : $@convention(c) (Int, Int8) -> Int // CHECK: apply [[ADD_TWO_TEMPLATES_FN]]({{.*}}) : $@convention(c) (Int, Int8) -> Int -// CHECK: [[REMOVE_REFERENCE_FN:%.*]] = function_ref @_ZN24HasStaticMemberTemplates15removeReferenceIlEET_RS1_ : $@convention(c) (@inout Int) -> Int +// CHECK: [[REMOVE_REFERENCE_FN:%.*]] = function_ref @{{_ZN24HasStaticMemberTemplates15removeReferenceIlEET_RS1_|\?\?\$removeReference@_J@HasStaticMemberTemplates@@SA_JAEA_J@Z}} : $@convention(c) (@inout Int) -> Int // CHECK: apply [[REMOVE_REFERENCE_FN]]({{.*}}) : $@convention(c) (@inout Int) -> Int // CHECK-LABEL: end sil function '$s4main17testStaticMembersyyF' @@ -69,8 +65,8 @@ func testStaticMembers() { HasStaticMemberTemplates.removeReference(&x) } -// CHECK: sil hidden_external [clang HasStaticMemberTemplates.add] @_ZN24HasStaticMemberTemplates3addIlEET_S1_S1_ : $@convention(c) (Int, Int) -> Int +// CHECK: sil hidden_external [clang HasStaticMemberTemplates.add] @{{_ZN24HasStaticMemberTemplates3addIlEET_S1_S1_|\?\?\$add@_J@HasStaticMemberTemplates@@SA_J_J0@Z}} : $@convention(c) (Int, Int) -> Int -// CHECK: sil hidden_external [clang HasStaticMemberTemplates.addTwoTemplates] @_ZN24HasStaticMemberTemplates15addTwoTemplatesIlcEET_S1_T0_ : $@convention(c) (Int, Int8) -> Int +// CHECK: sil hidden_external [clang HasStaticMemberTemplates.addTwoTemplates] @{{_ZN24HasStaticMemberTemplates15addTwoTemplatesIlcEET_S1_T0_|\?\?\$addTwoTemplates@_JD@HasStaticMemberTemplates@@SA_J_JD@Z}} : $@convention(c) (Int, Int8) -> Int -// CHECK: sil hidden_external [clang HasStaticMemberTemplates.removeReference] @_ZN24HasStaticMemberTemplates15removeReferenceIlEET_RS1_ : $@convention(c) (@inout Int) -> Int +// CHECK: sil hidden_external [clang HasStaticMemberTemplates.removeReference] @{{_ZN24HasStaticMemberTemplates15removeReferenceIlEET_RS1_|\?\?\$removeReference@_J@HasStaticMemberTemplates@@SA_JAEA_J@Z}} : $@convention(c) (@inout Int) -> Int diff --git a/test/Interop/Cxx/value-witness-table/Inputs/custom-destructors.h b/test/Interop/Cxx/value-witness-table/Inputs/custom-destructors.h index c2fe4b9e4c702..79aad99606d65 100644 --- a/test/Interop/Cxx/value-witness-table/Inputs/custom-destructors.h +++ b/test/Interop/Cxx/value-witness-table/Inputs/custom-destructors.h @@ -3,6 +3,12 @@ struct __attribute__((swift_attr("import_unsafe"))) HasUserProvidedDestructor { int *value; + HasUserProvidedDestructor() {} + HasUserProvidedDestructor(int *value) : value(value) {} +#if __is_target_os(windows) && !defined(WIN_TRIVIAL) + // On windows, force this type to be address-only. + HasUserProvidedDestructor(const HasUserProvidedDestructor &other) : value(other.value) {} +#endif ~HasUserProvidedDestructor() { *value = 42; } }; @@ -71,6 +77,11 @@ struct DummyStruct {}; struct __attribute__((swift_attr("import_unsafe"))) HasUserProvidedDestructorAndDummy { DummyStruct dummy; + HasUserProvidedDestructorAndDummy(DummyStruct dummy) : dummy(dummy) {} +#if __is_target_os(windows) && !defined(WIN_TRIVIAL) + // On windows, force this type to be address-only. + HasUserProvidedDestructorAndDummy(const HasUserProvidedDestructorAndDummy &other) : dummy(other.dummy) {} +#endif ~HasUserProvidedDestructorAndDummy() {} }; diff --git a/test/Interop/Cxx/value-witness-table/custom-destructors-non-virtual-irgen.swift b/test/Interop/Cxx/value-witness-table/custom-destructors-non-virtual-irgen.swift index edd25f6ba600a..1c1ba43ebb35c 100644 --- a/test/Interop/Cxx/value-witness-table/custom-destructors-non-virtual-irgen.swift +++ b/test/Interop/Cxx/value-witness-table/custom-destructors-non-virtual-irgen.swift @@ -6,7 +6,7 @@ import CustomDestructor protocol InitWithDummy { - init(dummy: DummyStruct) + init(_: DummyStruct) } extension HasUserProvidedDestructorAndDummy : InitWithDummy { } @@ -17,6 +17,7 @@ extension HasUserProvidedDestructorAndDummy : InitWithDummy { } // CHECK-LABEL: define {{.*}}void @"$s4main37testHasUserProvidedDestructorAndDummyyyF" // CHECK: [[OBJ:%.*]] = alloca %TSo33HasUserProvidedDestructorAndDummyV +// CHECK: [[CXX_OBJ_PRE:%.*]] = bitcast %TSo33HasUserProvidedDestructorAndDummyV* [[OBJ]] to %struct.HasUserProvidedDestructorAndDummy* // CHECK: [[CXX_OBJ:%.*]] = bitcast %TSo33HasUserProvidedDestructorAndDummyV* [[OBJ]] to %struct.HasUserProvidedDestructorAndDummy* // CHECK: call {{.*}}@{{_ZN33HasUserProvidedDestructorAndDummyD(1|2)Ev|"\?\?1HasUserProvidedDestructorAndDummy@@QEAA@XZ"}}(%struct.HasUserProvidedDestructorAndDummy* [[CXX_OBJ]]) // CHECK: ret void @@ -25,7 +26,7 @@ extension HasUserProvidedDestructorAndDummy : InitWithDummy { } // CHECK-LABEL: define {{.*}}@{{_ZN33HasUserProvidedDestructorAndDummyD(1|2)Ev|"\?\?1HasUserProvidedDestructorAndDummy@@QEAA@XZ"}} // CHECK: ret public func testHasUserProvidedDestructorAndDummy() { - _ = HasUserProvidedDestructorAndDummy(dummy: DummyStruct()) + _ = HasUserProvidedDestructorAndDummy(DummyStruct()) } // CHECK-LABEL: define {{.*}}void @"$s4main26testHasDefaultedDestructoryyF" diff --git a/test/Interop/Cxx/value-witness-table/custom-destructors-non-virtual.swift b/test/Interop/Cxx/value-witness-table/custom-destructors-non-virtual.swift index 1434e92cc7b5b..228dd5bce9f95 100644 --- a/test/Interop/Cxx/value-witness-table/custom-destructors-non-virtual.swift +++ b/test/Interop/Cxx/value-witness-table/custom-destructors-non-virtual.swift @@ -9,7 +9,7 @@ import StdlibUnittest var CXXDestructorTestSuite = TestSuite("CXXDestructor") protocol InitWithPtr { - init(value: UnsafeMutablePointer!) + init(_: UnsafeMutablePointer!) } extension HasUserProvidedDestructor : InitWithPtr { } @@ -26,14 +26,14 @@ extension HasEmptyDestructorAndMemberWithUserDefinedConstructor func withCxxDestructorSideEffects(_ _: inout T) { } func createTypeWithUserProvidedDestructor(_ ptr: UnsafeMutablePointer) { - var obj = HasUserProvidedDestructor(value: ptr) + var obj = HasUserProvidedDestructor(ptr) withCxxDestructorSideEffects(&obj) } func createTypeWithEmptyDestructorAndMemberWithUserDefinedConstructor( _ ptr: UnsafeMutablePointer ) { - let member = HasUserProvidedDestructor(value: ptr) + let member = HasUserProvidedDestructor(ptr) var obj = HasEmptyDestructorAndMemberWithUserDefinedConstructor(member: member) withCxxDestructorSideEffects(&obj) } @@ -41,7 +41,7 @@ func createTypeWithEmptyDestructorAndMemberWithUserDefinedConstructor( func createTypeWithNonTrivialImplicitDestructor( _ ptr: UnsafeMutablePointer ) { - let member = HasUserProvidedDestructor(value: ptr) + let member = HasUserProvidedDestructor(ptr) var obj = HasNonTrivialImplicitDestructor(member: member) withCxxDestructorSideEffects(&obj) } @@ -49,7 +49,7 @@ func createTypeWithNonTrivialImplicitDestructor( func createTypeWithNonTrivialDefaultDestructor( _ ptr: UnsafeMutablePointer ) { - let member = HasUserProvidedDestructor(value: ptr) + let member = HasUserProvidedDestructor(ptr) var obj = HasNonTrivialDefaultedDestructor(member: member) withCxxDestructorSideEffects(&obj) } @@ -58,7 +58,7 @@ func createTypeWithGeneric( _ ptr: UnsafeMutablePointer, type: T.Type ) { - var obj = T(value: ptr) + var obj = T(ptr) withCxxDestructorSideEffects(&obj) } @@ -66,7 +66,7 @@ func createTypeWithProtocol( _ ptr: UnsafeMutablePointer, type: InitWithPtr.Type ) { - var obj = type.self.init(value: ptr) + var obj = type.self.init(ptr) withCxxDestructorSideEffects(&obj) } @@ -75,7 +75,7 @@ func createTypeWithProtocol( type: InitWithPtr.Type, holder: InitWithMember.Type ) { - let member = type.self.init(value: ptr) + let member = type.self.init(ptr) var obj = holder.self.init(member: member as! HasUserProvidedDestructor) withCxxDestructorSideEffects(&obj) } diff --git a/test/Interop/Cxx/value-witness-table/custom-destructors-typechecker-trivial-windows-abi.swift b/test/Interop/Cxx/value-witness-table/custom-destructors-typechecker-trivial-windows-abi.swift new file mode 100644 index 0000000000000..8d555ad22672e --- /dev/null +++ b/test/Interop/Cxx/value-witness-table/custom-destructors-typechecker-trivial-windows-abi.swift @@ -0,0 +1,10 @@ +// RUN: %target-typecheck-verify-swift -I %S/Inputs -enable-experimental-cxx-interop -Xcc -DWIN_TRIVIAL + +// REQUIRES: OS=windows-msvc + +import CustomDestructor + +_ = HasUserProvidedDestructor() // expected-error {{non-trivial C++ class with trivial ABI is not yet available in Swift}} +_ = HasEmptyDestructorAndMemberWithUserDefinedConstructor() // expected-error {{non-trivial C++ class with trivial ABI is not yet available in Swift}} +_ = HasNonTrivialImplicitDestructor() // expected-error {{non-trivial C++ class with trivial ABI is not yet available in Swift}} +_ = HasNonTrivialDefaultedDestructor() // expected-error {{non-trivial C++ class with trivial ABI is not yet available in Swift}} diff --git a/test/Interop/CxxToSwiftToCxx/bridge-cxx-struct-back-to-cxx.swift b/test/Interop/CxxToSwiftToCxx/bridge-cxx-struct-back-to-cxx.swift index 550885c073905..a18b68e0a8968 100644 --- a/test/Interop/CxxToSwiftToCxx/bridge-cxx-struct-back-to-cxx.swift +++ b/test/Interop/CxxToSwiftToCxx/bridge-cxx-struct-back-to-cxx.swift @@ -37,7 +37,7 @@ namespace ns { T x; NonTrivialTemplate(); - NonTrivialTemplate(const NonTrivialTemplate &) = default; + NonTrivialTemplate(const NonTrivialTemplate &other) : x(other.x) {} NonTrivialTemplate(NonTrivialTemplate &&) = default; ~NonTrivialTemplate() {} }; @@ -46,6 +46,8 @@ namespace ns { struct NonTrivialImplicitMove { NonTrivialTemplate member; + + NonTrivialImplicitMove(const NonTrivialImplicitMove &other) : member(other.member) {} }; #define IMMORTAL_REF \ diff --git a/test/SILOptimizer/Inputs/CXXTypesWithUserProvidedDestructor.h b/test/SILOptimizer/Inputs/CXXTypesWithUserProvidedDestructor.h index f31f2af64883f..373b6e24b0593 100644 --- a/test/SILOptimizer/Inputs/CXXTypesWithUserProvidedDestructor.h +++ b/test/SILOptimizer/Inputs/CXXTypesWithUserProvidedDestructor.h @@ -2,16 +2,20 @@ #define TEST_SIL_OPTIMIZER_CXX_WITH_CUSTOM_DESTRUCTOR_H struct HasUserProvidedDestructor { - int x; + int x = 0; + + HasUserProvidedDestructor(const HasUserProvidedDestructor &other) : x(other.x) {} ~HasUserProvidedDestructor() {} }; struct Loadable { - int x; + int x = 0; }; struct HasMemberWithUserProvidedDestructor { Loadable y; + + HasMemberWithUserProvidedDestructor(const HasMemberWithUserProvidedDestructor &other) : y(other.y) {} ~HasMemberWithUserProvidedDestructor() {} };