From c6c942769bf70d80675d7d76cd44b67d3f4666ed Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Tue, 23 Apr 2024 14:01:12 -0700 Subject: [PATCH] Add a new parameter convention `@in_cxx` for non-trivial C++ classes that are passed indirectly and destructed by the caller Fix a bug where `@in`, which indicates the callee is responsible for destroying the passed object, was being used to pass such classes. rdar://122707697 --- .../Sources/SIL/Argument.swift | 25 ++- .../Sources/SIL/Effects.swift | 2 +- .../Sources/SIL/FunctionConvention.swift | 2 +- include/swift/AST/Types.h | 10 + include/swift/SIL/ApplySite.h | 1 + include/swift/SIL/SILArgumentConvention.h | 9 + include/swift/SIL/SILBridging.h | 2 + include/swift/SIL/SILDeclRef.h | 15 +- include/swift/SIL/SILFunctionConventions.h | 1 + lib/AST/ASTMangler.cpp | 1 + lib/AST/ASTPrinter.cpp | 2 + lib/Demangling/Demangler.cpp | 1 + lib/Demangling/Remangler.cpp | 1 + lib/IRGen/GenCall.cpp | 1 + lib/IRGen/GenDistributed.cpp | 1 + lib/IRGen/GenFunc.cpp | 5 + lib/IRGen/GenObjC.cpp | 1 + lib/IRGen/GenProto.cpp | 1 + lib/SIL/IR/OperandOwnership.cpp | 3 + lib/SIL/IR/SILDeclRef.cpp | 8 +- lib/SIL/IR/SILFunctionType.cpp | 26 ++- lib/SIL/IR/SILPrinter.cpp | 1 + lib/SIL/IR/SILValue.cpp | 1 + lib/SIL/Utils/MemAccessUtils.cpp | 1 + lib/SIL/Verifier/MemoryLifetimeVerifier.cpp | 2 + lib/SIL/Verifier/SILVerifier.cpp | 2 + lib/SILGen/SILGenApply.cpp | 7 +- lib/SILGen/SILGenBridging.cpp | 5 + lib/SILGen/SILGenBuilder.cpp | 1 + lib/SILGen/SILGenExpr.cpp | 2 +- lib/SILGen/SILGenPoly.cpp | 4 + lib/SILGen/SILGenProlog.cpp | 6 + .../Differentiation/VJPCloner.cpp | 1 + .../Mandatory/AddressLowering.cpp | 1 + .../Mandatory/DIMemoryUseCollector.cpp | 1 + .../Mandatory/MandatoryInlining.cpp | 1 + .../Mandatory/MoveOnlyAddressCheckerUtils.cpp | 3 + lib/SILOptimizer/Mandatory/MoveOnlyUtils.cpp | 3 +- .../Mandatory/PMOMemoryUseCollector.cpp | 1 + .../Mandatory/RawSILInstLowering.cpp | 1 + .../SILCombiner/SILCombinerApplyVisitors.cpp | 1 + .../Transforms/PartialApplySimplification.cpp | 6 + lib/SILOptimizer/Utils/CastOptimizer.cpp | 2 + lib/SILOptimizer/Utils/Generics.cpp | 1 + lib/Serialization/Deserialization.cpp | 1 + lib/Serialization/ModuleFormat.h | 1 + lib/Serialization/Serialization.cpp | 1 + test/Interop/Cxx/class/Inputs/closure.h | 27 ++- .../Cxx/class/closure-thunk-android.swift | 59 ++++++ .../closure-thunk-executable-macosx.swift | 19 ++ .../Cxx/class/closure-thunk-executable.swift | 4 - .../Cxx/class/closure-thunk-macosx.swift | 92 +++++++++ .../Cxx/class/closure-thunk-windows.swift | 57 ++++++ test/Interop/Cxx/class/closure-thunk.swift | 21 --- .../Cxx/class/function-call-macosx.swift | 34 ++++ .../Cxx/class/function-call-windows.swift | 17 ++ test/Interop/Cxx/class/function-call.swift | 33 ++++ ...ification-non-trivial-silgen-windows.swift | 176 ++++++++++++++++++ ...pe-classification-non-trivial-silgen.swift | 8 +- ...call-to-generated-init-with-nsstring.swift | 8 +- 60 files changed, 674 insertions(+), 56 deletions(-) create mode 100644 test/Interop/Cxx/class/closure-thunk-android.swift create mode 100644 test/Interop/Cxx/class/closure-thunk-executable-macosx.swift create mode 100644 test/Interop/Cxx/class/closure-thunk-macosx.swift create mode 100644 test/Interop/Cxx/class/closure-thunk-windows.swift create mode 100644 test/Interop/Cxx/class/function-call-macosx.swift create mode 100644 test/Interop/Cxx/class/function-call-windows.swift create mode 100644 test/Interop/Cxx/class/function-call.swift create mode 100644 test/Interop/Cxx/class/type-classification-non-trivial-silgen-windows.swift diff --git a/SwiftCompilerSources/Sources/SIL/Argument.swift b/SwiftCompilerSources/Sources/SIL/Argument.swift index 3a5c16631e329..c2dd8f38063ab 100644 --- a/SwiftCompilerSources/Sources/SIL/Argument.swift +++ b/SwiftCompilerSources/Sources/SIL/Argument.swift @@ -347,6 +347,11 @@ public enum ArgumentConvention : CustomStringConvertible { /// convention used by mutable captures in @noescape closures. case indirectInoutAliasable + /// This argument is passed indirectly, i.e. by directly passing the address + /// of an object in memory. The callee may modify, but does not destroy the + /// object. + case indirectInCXX + /// This argument represents an indirect return value address. The callee stores /// the returned value to this argument. At the time when the function is called, /// the memory location referenced by the argument is uninitialized. @@ -402,8 +407,9 @@ public enum ArgumentConvention : CustomStringConvertible { public var isIndirect: Bool { switch self { case .indirectIn, .indirectInGuaranteed, - .indirectInout, .indirectInoutAliasable, .indirectOut, - .packOut, .packInout, .packOwned, .packGuaranteed: + .indirectInout, .indirectInoutAliasable, .indirectInCXX, + .indirectOut, .packOut, .packInout, .packOwned, + .packGuaranteed: return true case .directOwned, .directUnowned, .directGuaranteed: return false @@ -416,7 +422,8 @@ public enum ArgumentConvention : CustomStringConvertible { .packOwned, .packGuaranteed: return true case .directOwned, .directUnowned, .directGuaranteed, - .indirectInout, .indirectInoutAliasable, .indirectOut, + .indirectInout, .indirectInoutAliasable, .indirectInCXX, + .indirectOut, .packOut, .packInout: return false } @@ -428,7 +435,7 @@ public enum ArgumentConvention : CustomStringConvertible { return true case .indirectInGuaranteed, .directGuaranteed, .packGuaranteed, .indirectIn, .directOwned, .directUnowned, - .indirectInout, .indirectInoutAliasable, + .indirectInout, .indirectInoutAliasable, .indirectInCXX, .packInout, .packOwned: return false } @@ -439,8 +446,8 @@ public enum ArgumentConvention : CustomStringConvertible { case .indirectInGuaranteed, .directGuaranteed, .packGuaranteed: return true case .indirectIn, .directOwned, .directUnowned, - .indirectInout, .indirectInoutAliasable, .indirectOut, - .packOut, .packInout, .packOwned: + .indirectInout, .indirectInoutAliasable, .indirectInCXX, + .indirectOut, .packOut, .packInout, .packOwned: return false } } @@ -451,6 +458,7 @@ public enum ArgumentConvention : CustomStringConvertible { .indirectOut, .indirectInGuaranteed, .indirectInout, + .indirectInCXX, .packOut, .packInout, .packOwned, @@ -475,6 +483,7 @@ public enum ArgumentConvention : CustomStringConvertible { case .indirectIn, .indirectOut, .indirectInGuaranteed, + .indirectInCXX, .directUnowned, .directGuaranteed, .directOwned, @@ -495,6 +504,8 @@ public enum ArgumentConvention : CustomStringConvertible { return "indirectInout" case .indirectInoutAliasable: return "indirectInoutAliasable" + case .indirectInCXX: + return "indirectInCXX" case .indirectOut: return "indirectOut" case .directOwned: @@ -529,6 +540,7 @@ extension BridgedArgumentConvention { case .Indirect_In_Guaranteed: return .indirectInGuaranteed case .Indirect_Inout: return .indirectInout case .Indirect_InoutAliasable: return .indirectInoutAliasable + case .Indirect_In_CXX: return .indirectInCXX case .Indirect_Out: return .indirectOut case .Direct_Owned: return .directOwned case .Direct_Unowned: return .directUnowned @@ -550,6 +562,7 @@ extension ArgumentConvention { case .indirectInGuaranteed: return .Indirect_In_Guaranteed case .indirectInout: return .Indirect_Inout case .indirectInoutAliasable: return .Indirect_InoutAliasable + case .indirectInCXX: return .Indirect_In_CXX case .indirectOut: return .Indirect_Out case .directOwned: return .Direct_Owned case .directUnowned: return .Direct_Unowned diff --git a/SwiftCompilerSources/Sources/SIL/Effects.swift b/SwiftCompilerSources/Sources/SIL/Effects.swift index 5ebab41da4ecc..6a3d5f20d13b9 100644 --- a/SwiftCompilerSources/Sources/SIL/Effects.swift +++ b/SwiftCompilerSources/Sources/SIL/Effects.swift @@ -561,7 +561,7 @@ public struct SideEffects : CustomStringConvertible, NoReflectionChildren { result.memory = SideEffects.Memory() } - case .indirectInout, .indirectInoutAliasable: + case .indirectInout, .indirectInoutAliasable, .indirectInCXX: break } return result diff --git a/SwiftCompilerSources/Sources/SIL/FunctionConvention.swift b/SwiftCompilerSources/Sources/SIL/FunctionConvention.swift index 2ce859a87a0d8..8cb90f1bbad13 100644 --- a/SwiftCompilerSources/Sources/SIL/FunctionConvention.swift +++ b/SwiftCompilerSources/Sources/SIL/FunctionConvention.swift @@ -164,7 +164,7 @@ public struct ParameterInfo : CustomStringConvertible { switch convention { case .indirectIn, .indirectInGuaranteed: return hasLoweredAddresses || type.isOpenedExistentialWithError() - case .indirectInout, .indirectInoutAliasable: + case .indirectInout, .indirectInoutAliasable, .indirectInCXX: return true case .directOwned, .directUnowned, .directGuaranteed: return false diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index a2de36188520c..6ef669861a1da 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -4059,6 +4059,11 @@ enum class ParameterConvention : uint8_t { /// convention used by mutable captures in @noescape closures. Indirect_InoutAliasable, + /// This argument is passed indirectly, i.e. by directly passing the address + /// of an object in memory. The callee may modify, but does not destroy the + /// object. + Indirect_In_CXX, + /// This argument is passed directly. Its type is non-trivial, and the callee /// is responsible for destroying it. Direct_Owned, @@ -4099,6 +4104,7 @@ inline bool isIndirectFormalParameter(ParameterConvention conv) { case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In_Guaranteed: return true; @@ -4121,6 +4127,7 @@ inline bool isConsumedParameter(ParameterConvention conv) { case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Direct_Unowned: case ParameterConvention::Direct_Guaranteed: case ParameterConvention::Indirect_In_Guaranteed: @@ -4143,6 +4150,7 @@ inline bool isGuaranteedParameter(ParameterConvention conv) { case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: case ParameterConvention::Direct_Unowned: case ParameterConvention::Direct_Owned: @@ -4157,6 +4165,7 @@ inline bool isMutatingParameter(ParameterConvention conv) { switch (conv) { case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Pack_Inout: return true; @@ -4183,6 +4192,7 @@ inline bool isPackParameter(ParameterConvention conv) { case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: case ParameterConvention::Direct_Guaranteed: case ParameterConvention::Direct_Unowned: diff --git a/include/swift/SIL/ApplySite.h b/include/swift/SIL/ApplySite.h index 6004c22da9008..b54a5f286e096 100644 --- a/include/swift/SIL/ApplySite.h +++ b/include/swift/SIL/ApplySite.h @@ -412,6 +412,7 @@ class ApplySite { : SILArgumentConvention::Direct_Owned; case SILArgumentConvention::Indirect_In: case SILArgumentConvention::Indirect_In_Guaranteed: + case SILArgumentConvention::Indirect_In_CXX: return pai->isOnStack() ? SILArgumentConvention::Indirect_In_Guaranteed : SILArgumentConvention::Indirect_In; case SILArgumentConvention::Pack_Guaranteed: diff --git a/include/swift/SIL/SILArgumentConvention.h b/include/swift/SIL/SILArgumentConvention.h index cb1ecb9aee171..60624729df40e 100644 --- a/include/swift/SIL/SILArgumentConvention.h +++ b/include/swift/SIL/SILArgumentConvention.h @@ -28,6 +28,7 @@ struct SILArgumentConvention { Indirect_In_Guaranteed, Indirect_Inout, Indirect_InoutAliasable, + Indirect_In_CXX, Indirect_Out, Direct_Owned, Direct_Unowned, @@ -55,6 +56,9 @@ struct SILArgumentConvention { case ParameterConvention::Indirect_In_Guaranteed: Value = SILArgumentConvention::Indirect_In_Guaranteed; return; + case ParameterConvention::Indirect_In_CXX: + Value = SILArgumentConvention::Indirect_In_CXX; + return; case ParameterConvention::Direct_Unowned: Value = SILArgumentConvention::Direct_Unowned; return; @@ -92,6 +96,7 @@ struct SILArgumentConvention { case SILArgumentConvention::Indirect_In_Guaranteed: case SILArgumentConvention::Indirect_In: case SILArgumentConvention::Indirect_Out: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Direct_Unowned: case SILArgumentConvention::Direct_Owned: case SILArgumentConvention::Direct_Guaranteed: @@ -114,6 +119,7 @@ struct SILArgumentConvention { case SILArgumentConvention::Indirect_Inout: case SILArgumentConvention::Indirect_Out: case SILArgumentConvention::Indirect_InoutAliasable: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Direct_Unowned: case SILArgumentConvention::Pack_Inout: case SILArgumentConvention::Pack_Guaranteed: @@ -133,6 +139,7 @@ struct SILArgumentConvention { case SILArgumentConvention::Indirect_In: case SILArgumentConvention::Indirect_Out: case SILArgumentConvention::Indirect_InoutAliasable: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Direct_Unowned: case SILArgumentConvention::Direct_Owned: case SILArgumentConvention::Pack_Inout: @@ -150,6 +157,7 @@ struct SILArgumentConvention { case SILArgumentConvention::Indirect_Out: case SILArgumentConvention::Indirect_In_Guaranteed: case SILArgumentConvention::Indirect_Inout: + case SILArgumentConvention::Indirect_In_CXX: return true; case SILArgumentConvention::Indirect_InoutAliasable: @@ -176,6 +184,7 @@ struct SILArgumentConvention { case SILArgumentConvention::Indirect_In_Guaranteed: case SILArgumentConvention::Indirect_Inout: case SILArgumentConvention::Indirect_InoutAliasable: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Direct_Unowned: case SILArgumentConvention::Direct_Guaranteed: case SILArgumentConvention::Direct_Owned: diff --git a/include/swift/SIL/SILBridging.h b/include/swift/SIL/SILBridging.h index abeabe161563c..cd443b0850573 100644 --- a/include/swift/SIL/SILBridging.h +++ b/include/swift/SIL/SILBridging.h @@ -136,6 +136,7 @@ enum class BridgedArgumentConvention { Indirect_In_Guaranteed, Indirect_Inout, Indirect_InoutAliasable, + Indirect_In_CXX, Indirect_Out, Direct_Owned, Direct_Unowned, @@ -167,6 +168,7 @@ struct BridgedParameterInfo { case BridgedArgumentConvention::Indirect_In_Guaranteed: return swift::ParameterConvention::Indirect_In_Guaranteed; case BridgedArgumentConvention::Indirect_Inout: return swift::ParameterConvention::Indirect_Inout; case BridgedArgumentConvention::Indirect_InoutAliasable: return swift::ParameterConvention::Indirect_InoutAliasable; + case BridgedArgumentConvention::Indirect_In_CXX: return swift::ParameterConvention::Indirect_In_CXX; case BridgedArgumentConvention::Indirect_Out: break; case BridgedArgumentConvention::Direct_Owned: return swift::ParameterConvention::Direct_Owned; case BridgedArgumentConvention::Direct_Unowned: return swift::ParameterConvention::Direct_Unowned; diff --git a/include/swift/SIL/SILDeclRef.h b/include/swift/SIL/SILDeclRef.h index 60619ec108982..91e637471fe61 100644 --- a/include/swift/SIL/SILDeclRef.h +++ b/include/swift/SIL/SILDeclRef.h @@ -200,6 +200,8 @@ struct SILDeclRef { /// Set if this is for an async let closure. unsigned isAsyncLetClosure : 1; + unsigned CFunctionPointer : 1; + PointerUnion pointer; @@ -234,7 +236,7 @@ struct SILDeclRef { : loc(), kind(Kind::Func), isForeign(0), isDistributed(0), isKnownToBeLocal(0), isRuntimeAccessible(0), backDeploymentKind(BackDeploymentKind::None), defaultArgIndex(0), - isAsyncLetClosure(0) {} + isAsyncLetClosure(0), CFunctionPointer(0) {} /// Produces a SILDeclRef of the given kind for the given decl. explicit SILDeclRef( @@ -257,11 +259,10 @@ struct SILDeclRef { /// for the containing ClassDecl. /// - If 'loc' is a global VarDecl, this returns its GlobalAccessor /// SILDeclRef. - explicit SILDeclRef( - Loc loc, - bool isForeign = false, - bool isDistributed = false, - bool isDistributedLocal = false); + explicit SILDeclRef(Loc loc, bool isForeign = false, + bool isDistributed = false, + bool isDistributedLocal = false, + bool isCFunctionPointer = false); /// See above put produces a prespecialization according to the signature. explicit SILDeclRef(Loc loc, GenericSignature prespecializationSig); @@ -290,6 +291,8 @@ struct SILDeclRef { bool hasAutoClosureExpr() const; bool hasFuncDecl() const; + bool hasCFunctionPointer() const { return CFunctionPointer; } + ValueDecl *getDecl() const { return loc.dyn_cast(); } AbstractClosureExpr *getAbstractClosureExpr() const { return loc.dyn_cast(); diff --git a/include/swift/SIL/SILFunctionConventions.h b/include/swift/SIL/SILFunctionConventions.h index ed61f86e4ca4c..91b5323cd06f2 100644 --- a/include/swift/SIL/SILFunctionConventions.h +++ b/include/swift/SIL/SILFunctionConventions.h @@ -592,6 +592,7 @@ inline bool SILModuleConventions::isIndirectSILParam(SILParameterInfo param, case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: + case ParameterConvention::Indirect_In_CXX: return isTypeIndirectForIndirectParamConvention(param.getInterfaceType(), loweredAddresses); case ParameterConvention::Indirect_Inout: diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index d5c1fb932144f..50eca275059be 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1136,6 +1136,7 @@ static char getParamConvention(ParameterConvention conv) { case ParameterConvention::Indirect_Inout: return 'l'; case ParameterConvention::Indirect_InoutAliasable: return 'b'; case ParameterConvention::Indirect_In_Guaranteed: return 'n'; + case ParameterConvention::Indirect_In_CXX: return 'C'; case ParameterConvention::Direct_Owned: return 'x'; case ParameterConvention::Direct_Unowned: return 'y'; case ParameterConvention::Direct_Guaranteed: return 'g'; diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 3f7f19da48e41..1e23d1896f11b 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -6731,6 +6731,7 @@ class TypePrinter : public TypeVisitor { case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In_Guaranteed: llvm_unreachable("callee convention cannot be indirect"); case ParameterConvention::Pack_Guaranteed: @@ -7500,6 +7501,7 @@ StringRef swift::getStringForParameterConvention(ParameterConvention conv) { case ParameterConvention::Indirect_In_Guaranteed: return "@in_guaranteed "; case ParameterConvention::Indirect_Inout: return "@inout "; case ParameterConvention::Indirect_InoutAliasable: return "@inout_aliasable "; + case ParameterConvention::Indirect_In_CXX: return "@in_cxx "; case ParameterConvention::Direct_Owned: return "@owned "; case ParameterConvention::Direct_Unowned: return ""; case ParameterConvention::Direct_Guaranteed: return "@guaranteed "; diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index cf331126c90d8..a5309bd95a383 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -2160,6 +2160,7 @@ NodePointer Demangler::demangleImplParamConvention(Node::Kind ConvKind) { case 'l': attr = "@inout"; break; case 'b': attr = "@inout_aliasable"; break; case 'n': attr = "@in_guaranteed"; break; + case 'C': attr = "@in_cxx"; break; case 'x': attr = "@owned"; break; case 'g': attr = "@guaranteed"; break; case 'e': attr = "@deallocating"; break; diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 9ebb78dd4e4e3..429a9d3bc96d6 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -2109,6 +2109,7 @@ ManglingError Remangler::mangleImplFunctionType(Node *node, unsigned depth) { .Case("@inout", 'l') .Case("@inout_aliasable", 'b') .Case("@in_guaranteed", 'n') + .Case("@in_cxx", 'C') .Case("@in_constant", 'c') .Case("@owned", 'x') .Case("@guaranteed", 'g') diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index b06534faec1bf..b3d93d6d0dd5a 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -1638,6 +1638,7 @@ const TypeInfo &SignatureExpansion::expand(SILParameterInfo param) { switch (auto conv = param.getConvention()) { case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: + case ParameterConvention::Indirect_In_CXX: addIndirectValueParameterAttributes(IGM, Attrs, ti, ParamIRTypes.size()); addPointerParameter(IGM.getStorageType(getSILFuncConventions().getSILType( param, IGM.getMaximalTypeExpansionContext()))); diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index 77467375d68f7..b35e73535ca39 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -544,6 +544,7 @@ void DistributedAccessor::decodeArgument(unsigned argumentIdx, break; } + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In_Guaranteed: { // The argument is +0, so we can use the address of the param in // the context directly. diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp index 37e4cf848b776..8d6c92fe529e3 100644 --- a/lib/IRGen/GenFunc.cpp +++ b/lib/IRGen/GenFunc.cpp @@ -846,6 +846,7 @@ CanType irgen::getArgumentLoweringType(CanType type, SILParameterInfo paramInfo, // address. case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: + case ParameterConvention::Indirect_In_CXX: if (isNoEscape) return CanInOutType::get(type); else @@ -1508,6 +1509,7 @@ static llvm::Value *emitPartialApplicationForwarder( break; case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Pack_Guaranteed: @@ -1625,6 +1627,7 @@ static llvm::Value *emitPartialApplicationForwarder( break; case ParameterConvention::Indirect_In_Guaranteed: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Direct_Guaranteed: dependsOnContextLifetime = true; if (outType->getCalleeConvention() == @@ -1750,6 +1753,7 @@ static llvm::Value *emitPartialApplicationForwarder( } break; } + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In_Guaranteed: if (outType->isNoEscape()) { cast(fieldTI).loadAsCopy(subIGF, fieldAddr, param); @@ -2301,6 +2305,7 @@ std::optional irgen::emitFunctionPartialApplication( switch (argConventions[i]) { // Take indirect value arguments out of memory. case ParameterConvention::Indirect_In: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In_Guaranteed: { if (outType->isNoEscape()) { cast(fieldLayout.getType()) diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp index d36e5b17af788..4a2664dfef4ed 100644 --- a/lib/IRGen/GenObjC.cpp +++ b/lib/IRGen/GenObjC.cpp @@ -948,6 +948,7 @@ static llvm::Function *emitObjCPartialApplicationForwarder(IRGenModule &IGM, case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Pack_Guaranteed: case ParameterConvention::Pack_Owned: case ParameterConvention::Pack_Inout: diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 02d9f10ef2374..7ed1918286a99 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -393,6 +393,7 @@ void PolymorphicConvention::considerParameter(SILParameterInfo param, case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: if (!isSelfParameter) return; if (type->getNominalOrBoundGenericNominal()) { considerNewTypeSource(IsExact, diff --git a/lib/SIL/IR/OperandOwnership.cpp b/lib/SIL/IR/OperandOwnership.cpp index 88fccc0991a57..81ef1103eefbc 100644 --- a/lib/SIL/IR/OperandOwnership.cpp +++ b/lib/SIL/IR/OperandOwnership.cpp @@ -505,6 +505,9 @@ static OperandOwnership getFunctionArgOwnership(SILArgumentConvention argConv, case SILArgumentConvention::Direct_Unowned: return OperandOwnership::UnownedInstantaneousUse; + case SILArgumentConvention::Indirect_In_CXX: + return OperandOwnership::InstantaneousUse; + case SILArgumentConvention::Indirect_Out: case SILArgumentConvention::Indirect_Inout: case SILArgumentConvention::Indirect_InoutAliasable: diff --git a/lib/SIL/IR/SILDeclRef.cpp b/lib/SIL/IR/SILDeclRef.cpp index 346c21e44e6e3..e985f68720c00 100644 --- a/lib/SIL/IR/SILDeclRef.cpp +++ b/lib/SIL/IR/SILDeclRef.cpp @@ -131,13 +131,14 @@ SILDeclRef::SILDeclRef(ValueDecl *vd, SILDeclRef::Kind kind, bool isForeign, isKnownToBeLocal(isKnownToBeLocal), isRuntimeAccessible(isRuntimeAccessible), backDeploymentKind(backDeploymentKind), defaultArgIndex(0), - isAsyncLetClosure(0), pointer(derivativeId) {} + isAsyncLetClosure(0), CFunctionPointer(0), pointer(derivativeId) {} SILDeclRef::SILDeclRef(SILDeclRef::Loc baseLoc, bool asForeign, - bool asDistributed, bool asDistributedKnownToBeLocal) + bool asDistributed, bool asDistributedKnownToBeLocal, + bool asCFunctionPointer) : isRuntimeAccessible(false), backDeploymentKind(SILDeclRef::BackDeploymentKind::None), - defaultArgIndex(0), isAsyncLetClosure(0), + defaultArgIndex(0), isAsyncLetClosure(0), CFunctionPointer(0), pointer((AutoDiffDerivativeFunctionIdentifier *)nullptr) { if (auto *vd = baseLoc.dyn_cast()) { if (auto *fd = dyn_cast(vd)) { @@ -181,6 +182,7 @@ SILDeclRef::SILDeclRef(SILDeclRef::Loc baseLoc, bool asForeign, llvm_unreachable("impossible SILDeclRef loc"); } + CFunctionPointer = asCFunctionPointer; isForeign = asForeign; isDistributed = asDistributed; isKnownToBeLocal = asDistributedKnownToBeLocal; diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 3d169e28817b1..14a9108d2119b 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -713,6 +713,7 @@ static CanSILFunctionType getAutoDiffPullbackType( case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: conv = ResultConvention::Indirect; break; } @@ -1050,6 +1051,7 @@ CanSILFunctionType SILFunctionType::getAutoDiffTransposeFunctionType( case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: newConv = ResultConvention::Indirect; break; } @@ -3335,6 +3337,11 @@ static ParameterConvention getIndirectCParameterConvention(clang::QualType type) // A trivial const * parameter in C should be considered @in. if (importer::isCxxConstReferenceType(type.getTypePtr())) return ParameterConvention::Indirect_In_Guaranteed; + if (auto *decl = type->getAsRecordDecl()) { + if (!decl->isParamDestroyedInCallee()) + return ParameterConvention::Indirect_In_CXX; + return ParameterConvention::Indirect_In; + } return ParameterConvention::Indirect_In; } @@ -4109,6 +4116,13 @@ static CanSILFunctionType getUncachedSILFunctionTypeForConstant( } } + // The type of the native-to-foreign thunk for a swift closure. + if (constant.isForeign && constant.hasClosureExpr()) { + AbstractionPattern pattern = AbstractionPattern(origLoweredInterfaceType); + return getSILFunctionTypeForAbstractCFunction( + TC, pattern, origLoweredInterfaceType, extInfoBuilder, constant); + } + // If the decl belongs to an ObjC method family, use that family's // ownership conventions. return getSILFunctionTypeForObjCSelectorFamily( @@ -4606,10 +4620,18 @@ static AbstractFunctionDecl *getBridgedFunction(SILDeclRef declRef) { static AbstractionPattern getAbstractionPatternForConstant(ASTContext &ctx, SILDeclRef constant, CanAnyFunctionType fnType, - unsigned numParameterLists) { + unsigned numParameterLists, + TypeConverter &TC) { if (!constant.isForeign) return AbstractionPattern(fnType); + // Native-to-foreign thunk for a swift closure. + if (constant.hasCFunctionPointer() && constant.hasClosureExpr()) { + auto clangType = TC.Context.getClangFunctionType( + fnType->getParams(), fnType->getResult(), FunctionTypeRepresentation::CFunctionPointer); + return AbstractionPattern(fnType, clangType); + } + auto bridgedFn = getBridgedFunction(constant); if (!bridgedFn) return AbstractionPattern(fnType); @@ -4657,7 +4679,7 @@ TypeConverter::getLoweredFormalTypes(SILDeclRef constant, // Form an abstraction pattern for bridging purposes. AbstractionPattern bridgingFnPattern = getAbstractionPatternForConstant(Context, constant, fnType, - numParameterLists); + numParameterLists, *this); auto extInfo = fnType->getExtInfo(); SILFunctionTypeRepresentation rep = getDeclRefRepresentation(constant); diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 2a9a97d52994f..b975cd0b9c833 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -1589,6 +1589,7 @@ class SILPrinter : public SILInstructionVisitor { case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Pack_Guaranteed: case ParameterConvention::Pack_Owned: case ParameterConvention::Pack_Inout: diff --git a/lib/SIL/IR/SILValue.cpp b/lib/SIL/IR/SILValue.cpp index ff0b9decc4760..9d6699f7d631e 100644 --- a/lib/SIL/IR/SILValue.cpp +++ b/lib/SIL/IR/SILValue.cpp @@ -313,6 +313,7 @@ ValueOwnershipKind::ValueOwnershipKind(const SILFunction &F, SILType Type, break; case SILArgumentConvention::Indirect_Inout: case SILArgumentConvention::Indirect_InoutAliasable: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Indirect_Out: case SILArgumentConvention::Pack_Inout: case SILArgumentConvention::Pack_Out: diff --git a/lib/SIL/Utils/MemAccessUtils.cpp b/lib/SIL/Utils/MemAccessUtils.cpp index 8fd94da177936..2d8c1cda84c3e 100644 --- a/lib/SIL/Utils/MemAccessUtils.cpp +++ b/lib/SIL/Utils/MemAccessUtils.cpp @@ -2193,6 +2193,7 @@ bool GatherUniqueStorageUses::visitUse(Operand *use, AccessUseType useTy) { case SILArgumentConvention::Indirect_Inout: case SILArgumentConvention::Indirect_InoutAliasable: case SILArgumentConvention::Indirect_Out: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Pack_Inout: case SILArgumentConvention::Pack_Out: return visitApplyOperand(use, visitor, diff --git a/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp b/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp index 4141eea623551..3ec464b912b87 100644 --- a/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp +++ b/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp @@ -578,6 +578,7 @@ void MemoryLifetimeVerifier::setFuncOperandBits(BlockState &state, Operand &op, case SILArgumentConvention::Indirect_In_Guaranteed: case SILArgumentConvention::Indirect_Inout: case SILArgumentConvention::Indirect_InoutAliasable: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Direct_Owned: case SILArgumentConvention::Direct_Unowned: case SILArgumentConvention::Direct_Guaranteed: @@ -901,6 +902,7 @@ void MemoryLifetimeVerifier::checkFuncArgument(Bits &bits, Operand &argumentOp, locations.setBits(bits, argumentOp.get()); break; case SILArgumentConvention::Indirect_In_Guaranteed: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Indirect_Inout: requireBitsSetForArgument(bits, &argumentOp); break; diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 614af77184816..ebae866be29cb 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -526,6 +526,7 @@ struct ImmutableAddressUseVerifier { case SILArgumentConvention::Indirect_Out: case SILArgumentConvention::Indirect_In: case SILArgumentConvention::Indirect_Inout: + case SILArgumentConvention::Indirect_In_CXX: return true; case SILArgumentConvention::Direct_Unowned: @@ -6396,6 +6397,7 @@ class SILVerifier : public SILVerifierBase { case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: case ParameterConvention::Indirect_In_Guaranteed: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Pack_Owned: case ParameterConvention::Pack_Guaranteed: case ParameterConvention::Pack_Inout: diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index a6ea1cc354638..f734b5f356bee 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -4355,8 +4355,9 @@ class ArgEmitter { SILParameterInfo param) { bool requiresReabstraction = loweredArgType.getASTType() != param.getInterfaceType(); - // If the parameter is consumed, we have to emit at +1. - if (param.isConsumed()) { + // If the parameter is consumed or @in_cxx, we have to emit at +1. + if (param.isConsumed() || + param.getConvention() == ParameterConvention::Indirect_In_CXX) { return {SGFContext(), requiresReabstraction}; } @@ -5596,6 +5597,7 @@ RValue SILGenFunction::emitApply( case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Pack_Guaranteed: case ParameterConvention::Pack_Owned: case ParameterConvention::Pack_Inout: @@ -6846,6 +6848,7 @@ bool AccessorBaseArgPreparer::shouldLoadBaseAddress() const { // memory to 'in', and we have pass at +1. case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: + case ParameterConvention::Indirect_In_CXX: // TODO: We shouldn't be able to get an lvalue here, but the AST // sometimes produces an inout base for non-mutating accessors. // rdar://problem/19782170 diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index 4e9a64da08978..86a5822b1aa6a 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -317,6 +317,9 @@ static ManagedValue emitManagedParameter(SILGenFunction &SGF, SILLocation loc, case ParameterConvention::Indirect_Inout: return ManagedValue::forLValue(value); + case ParameterConvention::Indirect_In_CXX: + return ManagedValue::forLValue(value); + case ParameterConvention::Indirect_In_Guaranteed: if (valueTL.isLoadable()) { return SGF.B.createLoadBorrow( @@ -438,6 +441,7 @@ static void buildFuncToBlockInvokeBody(SILGenFunction &SGF, case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Pack_Guaranteed: case ParameterConvention::Pack_Owned: case ParameterConvention::Pack_Inout: @@ -2173,6 +2177,7 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { case ParameterConvention::Indirect_In: param = emitManagedRValueWithCleanup(paramValue); break; + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In_Guaranteed: { auto tmp = emitTemporaryAllocation(fd, paramValue->getType()); B.createCopyAddr(fd, paramValue, tmp, IsNotTake, IsInitialization); diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp index 0534d720433fb..d7e7fd7a9d42e 100644 --- a/lib/SILGen/SILGenBuilder.cpp +++ b/lib/SILGen/SILGenBuilder.cpp @@ -573,6 +573,7 @@ static ManagedValue createInputFunctionArgument( case SILArgumentConvention::Indirect_Inout: case SILArgumentConvention::Indirect_InoutAliasable: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Pack_Inout: // An inout parameter is +0 and guaranteed, but represents an lvalue. return ManagedValue::forLValue(arg); diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 29d378d31ac47..f20cc20f524e2 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -1798,7 +1798,7 @@ ManagedValue emitCFunctionPointer(SILGenFunction &SGF, } // Produce a reference to the C-compatible entry point for the function. - SILDeclRef constant(loc, /*foreign*/ true); + SILDeclRef constant(loc, /*foreign*/ true, false, false, true); SILConstantInfo constantInfo = SGF.getConstantInfo(SGF.getTypeExpansionContext(), constant); diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 724a6df31660e..cd4bac30f84a9 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -2024,6 +2024,7 @@ class TranslateArguments : public ExpanderBase { return processIntoGuaranteed(innerOrigType, innerSubstType, outerOrigType, outerSubstType, outer, innerTy); + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: { if (SGF.silConv.useLoweredAddresses()) { return processIndirect(innerOrigType, innerSubstType, @@ -2218,6 +2219,7 @@ class TranslateArguments : public ExpanderBase { case ParameterConvention::Direct_Unowned: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: llvm_unreachable("not a pack convention"); @@ -2657,6 +2659,7 @@ ManagedValue TranslateArguments::expandPackInnerParam( case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Direct_Owned: case ParameterConvention::Direct_Unowned: case ParameterConvention::Direct_Guaranteed: @@ -2812,6 +2815,7 @@ static ManagedValue manageYield(SILGenFunction &SGF, SILValue value, if (value->getOwnershipKind() == OwnershipKind::None) return ManagedValue::forObjectRValueWithoutOwnership(value); return ManagedValue::forBorrowedObjectRValue(value); + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In_Guaranteed: { if (SGF.silConv.useLoweredAddresses()) { return ManagedValue::forBorrowedAddressRValue(value); diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index bcdfd3e61cd56..b514e0f7e720c 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -915,6 +915,12 @@ class ArgumentInitHelper { MarkUnresolvedNonCopyableValueInst::CheckKind:: ConsumableAndAssignable); break; + case SILArgumentConvention::Indirect_In_CXX: + argrv = SGF.B.createMarkUnresolvedNonCopyableValueInst( + loc, argrv, + MarkUnresolvedNonCopyableValueInst::CheckKind:: + AssignableButNotConsumable); + break; case SILArgumentConvention::Indirect_In_Guaranteed: argrv = SGF.B.createMarkUnresolvedNonCopyableValueInst( loc, argrv, diff --git a/lib/SILOptimizer/Differentiation/VJPCloner.cpp b/lib/SILOptimizer/Differentiation/VJPCloner.cpp index b329e6ea4dd97..b0e6bb971cfb3 100644 --- a/lib/SILOptimizer/Differentiation/VJPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/VJPCloner.cpp @@ -1157,6 +1157,7 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: conv = ResultConvention::Indirect; break; case ParameterConvention::Pack_Guaranteed: diff --git a/lib/SILOptimizer/Mandatory/AddressLowering.cpp b/lib/SILOptimizer/Mandatory/AddressLowering.cpp index 4e3afad7cc65e..5f440d2dc93fc 100644 --- a/lib/SILOptimizer/Mandatory/AddressLowering.cpp +++ b/lib/SILOptimizer/Mandatory/AddressLowering.cpp @@ -3226,6 +3226,7 @@ void YieldRewriter::rewriteOperand(YieldInst *yieldInst, unsigned index) { return; case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: return; case ParameterConvention::Indirect_In: ownership = OwnershipKind::Owned; diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp index cb3615c3a564c..c42bc474388dd 100644 --- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp +++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp @@ -1014,6 +1014,7 @@ void ElementUseCollector::collectUses(SILValue Pointer, unsigned BaseEltNo) { LLVM_FALLTHROUGH; } + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_Inout: { // If we're in the initializer for a struct, and this is a call to a // mutating method, we model that as an escape of self. If an diff --git a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp index 67acaf247a5d1..337f579adee60 100644 --- a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp +++ b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp @@ -125,6 +125,7 @@ static bool fixupReferenceCounts( case ParameterConvention::Pack_Inout: break; + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In_Guaranteed: { // Do the same as for Direct_Guaranteed, just the address version. // (See comment below). diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp index 9939f7da42ec3..0f03056c381e9 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp @@ -424,6 +424,7 @@ static bool visitScopeEndsRequiringInit( case SILArgumentConvention::Indirect_In: case SILArgumentConvention::Indirect_Out: case SILArgumentConvention::Indirect_In_Guaranteed: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Direct_Guaranteed: case SILArgumentConvention::Direct_Owned: case SILArgumentConvention::Direct_Unowned: @@ -1016,6 +1017,7 @@ void UseState::initializeLiveness( case swift::SILArgumentConvention::Indirect_In_Guaranteed: case swift::SILArgumentConvention::Indirect_Inout: case swift::SILArgumentConvention::Indirect_InoutAliasable: + case swift::SILArgumentConvention::Indirect_In_CXX: // We need to add our address to the initInst array to make sure that // later invariants that we assert upon remain true. LLVM_DEBUG( @@ -2532,6 +2534,7 @@ bool GatherUsesVisitor::visitUse(Operand *op) { case SILArgumentConvention::Indirect_Inout: case SILArgumentConvention::Indirect_InoutAliasable: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Indirect_In: case SILArgumentConvention::Indirect_Out: case SILArgumentConvention::Direct_Unowned: diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyUtils.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyUtils.cpp index afac7a3563571..9d7ea0af1da81 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyUtils.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyUtils.cpp @@ -259,7 +259,8 @@ bool noncopyable::memInstMustReinitialize(Operand *memOper) { case SILInstructionKind::TryApplyInst: case SILInstructionKind::ApplyInst: { FullApplySite applySite(memInst); - return applySite.getCaptureConvention(*memOper).isInoutConvention(); + auto conv = applySite.getCaptureConvention(*memOper); + return conv.isInoutConvention() || conv == SILArgumentConvention::Indirect_In_CXX; } case SILInstructionKind::StoreInst: return cast(memInst)->getOwnershipQualifier() == diff --git a/lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp index 0c4d3216870d8..c5aa73e77f36a 100644 --- a/lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp +++ b/lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp @@ -402,6 +402,7 @@ bool ElementUseCollector::collectUses(SILValue Pointer) { // If this is an @inout parameter, it is like both a load and store. case ParameterConvention::Indirect_Inout: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_InoutAliasable: { // If we're in the initializer for a struct, and this is a call to a // mutating method, we model that as an escape of self. If an diff --git a/lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp b/lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp index 36c8b0d271771..3d0adbdab7d07 100644 --- a/lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp +++ b/lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp @@ -149,6 +149,7 @@ static void getAssignByWrapperArgsRecursively(SmallVectorImpl &args, case SILArgumentConvention::Indirect_Inout: case SILArgumentConvention::Indirect_InoutAliasable: case SILArgumentConvention::Indirect_Out: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Pack_Inout: case SILArgumentConvention::Pack_Guaranteed: case SILArgumentConvention::Pack_Owned: diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp index 97dfaeb3e3a58..e6182d2efb801 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp @@ -679,6 +679,7 @@ bool SILCombiner::eraseApply(FullApplySite FAS, const UserListTy &Users) { case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Direct_Unowned: case ParameterConvention::Direct_Guaranteed: case ParameterConvention::Pack_Guaranteed: diff --git a/lib/SILOptimizer/Transforms/PartialApplySimplification.cpp b/lib/SILOptimizer/Transforms/PartialApplySimplification.cpp index 7e017ae0ff153..9c8e1fbe8f66a 100644 --- a/lib/SILOptimizer/Transforms/PartialApplySimplification.cpp +++ b/lib/SILOptimizer/Transforms/PartialApplySimplification.cpp @@ -181,6 +181,8 @@ static bool isSimplePartialApply(SILModule &M, case ParameterConvention::Direct_Owned: case ParameterConvention::Indirect_In: return false; + case ParameterConvention::Indirect_In_CXX: + llvm_unreachable("Should never hit this"); } } else { if (contextParam.isFormalIndirect()) { @@ -454,6 +456,7 @@ rewriteKnownCalleeWithExplicitContext(SILFunction *callee, case ParameterConvention::Direct_Unowned: case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Pack_Guaranteed: case ParameterConvention::Pack_Owned: boxFields.push_back(SILField(param.getInterfaceType(), /*mutable*/false)); @@ -619,6 +622,7 @@ rewriteKnownCalleeWithExplicitContext(SILFunction *callee, break; } case ParameterConvention::Indirect_In_Guaranteed: + case ParameterConvention::Indirect_In_CXX: // We can borrow the value in-place in the box. projectedArg = proj; break; @@ -665,6 +669,7 @@ rewriteKnownCalleeWithExplicitContext(SILFunction *callee, break; } case ParameterConvention::Indirect_In_Guaranteed: + case ParameterConvention::Indirect_In_CXX: // We can borrow the value in-place in the box. projectedArg = proj; break; @@ -790,6 +795,7 @@ rewriteKnownCalleeWithExplicitContext(SILFunction *callee, case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_In: + case ParameterConvention::Indirect_In_CXX: // Move the value from its current memory location to the box. B.createCopyAddr(loc, arg, proj, IsTake, IsInitialization); break; diff --git a/lib/SILOptimizer/Utils/CastOptimizer.cpp b/lib/SILOptimizer/Utils/CastOptimizer.cpp index e56ed4ff75c74..21b9cbbcf1edf 100644 --- a/lib/SILOptimizer/Utils/CastOptimizer.cpp +++ b/lib/SILOptimizer/Utils/CastOptimizer.cpp @@ -721,6 +721,8 @@ CastOptimizer::optimizeBridgedSwiftToObjCCast(SILDynamicCastInst dynamicCast) { case ParameterConvention::Indirect_InoutAliasable: // TODO handle remaining indirect argument types return nullptr; + case ParameterConvention::Indirect_In_CXX: + llvm_unreachable("Should never hit this"); } // Generate a code to invoke the bridging function. diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index ec02377b9488d..fe6a778a3ac66 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -786,6 +786,7 @@ void ReabstractionInfo::createSubstitutedAndSpecializedTypes() { } case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Pack_Inout: case ParameterConvention::Pack_Owned: case ParameterConvention::Pack_Guaranteed: diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 52657105150e5..75f5f49db53e8 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -6578,6 +6578,7 @@ getActualParameterConvention(uint8_t raw) { CASE(Indirect_In) CASE(Indirect_Inout) CASE(Indirect_InoutAliasable) + CASE(Indirect_In_CXX) CASE(Indirect_In_Guaranteed) case serialization::ParameterConvention::Indirect_In_Constant: \ return swift::ParameterConvention::Indirect_In; diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 9ec878b7f1580..789a02c9affd6 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -388,6 +388,7 @@ enum class ParameterConvention : uint8_t { Pack_Owned, Pack_Inout, Pack_Guaranteed, + Indirect_In_CXX, }; using ParameterConventionField = BCFixed<4>; diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index a45150c005c77..351085ca8e837 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -5175,6 +5175,7 @@ static uint8_t getRawStableParameterConvention(swift::ParameterConvention pc) { SIMPLE_CASE(ParameterConvention, Indirect_In_Guaranteed) SIMPLE_CASE(ParameterConvention, Indirect_Inout) SIMPLE_CASE(ParameterConvention, Indirect_InoutAliasable) + SIMPLE_CASE(ParameterConvention, Indirect_In_CXX) SIMPLE_CASE(ParameterConvention, Direct_Owned) SIMPLE_CASE(ParameterConvention, Direct_Unowned) SIMPLE_CASE(ParameterConvention, Direct_Guaranteed) diff --git a/test/Interop/Cxx/class/Inputs/closure.h b/test/Interop/Cxx/class/Inputs/closure.h index ac5f8f8beca39..9284edb5e6631 100644 --- a/test/Interop/Cxx/class/Inputs/closure.h +++ b/test/Interop/Cxx/class/Inputs/closure.h @@ -4,12 +4,37 @@ struct NonTrivial { NonTrivial() { p = new int(123); } ~NonTrivial() { delete p; } - NonTrivial(const NonTrivial &other); + NonTrivial(const NonTrivial &other) { + p = new int(*other.p); + } int *p; }; +void cfunc(void (^ _Nonnull block)(NonTrivial)) { + block(NonTrivial()); +} + void cfunc2(void (*fp)(NonTrivial)) { (*fp)(NonTrivial()); } +struct ARCWeak { +#if __OBJC__ + __weak _Nullable id m; +#endif +}; + +void cfuncARCWeak(void (^ _Nonnull block)(ARCWeak)) { + block(ARCWeak()); +} + +void cfunc(NonTrivial); +void cfuncARCWeak(ARCWeak); + +typedef void (*FnPtr)(NonTrivial); +FnPtr _Nonnull getFnPtr(); + +typedef void (*FnPtr2)(ARCWeak); +FnPtr2 _Nonnull getFnPtr2(); + #endif // __CLOSURE__ diff --git a/test/Interop/Cxx/class/closure-thunk-android.swift b/test/Interop/Cxx/class/closure-thunk-android.swift new file mode 100644 index 0000000000000..4933811c73ca6 --- /dev/null +++ b/test/Interop/Cxx/class/closure-thunk-android.swift @@ -0,0 +1,59 @@ +// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-silgen %s | %FileCheck --dump-input-filter=all %s + +// REQUIRES: OS=linux-android + +import Closure + +// CHECK: sil [ossa] @$s4main18testClosureToBlockyyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = function_ref @$s4main18testClosureToBlockyyFySo10NonTrivialVcfU_ : $@convention(thin) (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V1:.*]] = thin_to_thick_function %[[V0]] : $@convention(thin) (@in_guaranteed NonTrivial) -> () to $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V2:.*]] = alloc_stack $@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V3:.*]] = project_block_storage %[[V2]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: store %[[V1]] to [trivial] %[[V3]] : $*@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V7:.*]] = function_ref @$sSo10NonTrivialVIegn_ABIeyBn_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), @in_guaranteed NonTrivial) -> () +// CHECK: %[[V6:.*]] = init_block_storage_header %[[V2]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), invoke %[[V7]] : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), @in_guaranteed NonTrivial) -> (), type $@convention(block) (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V8:.*]] = copy_block %[[V6]] : $@convention(block) (@in_guaranteed NonTrivial) -> () +// CHECK: dealloc_stack %[[V2]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V11:.*]] = function_ref @_Z5cfuncU13block_pointerFv10NonTrivialE : $@convention(c) (@convention(block) (@in_guaranteed NonTrivial) -> ()) -> () +// CHECK: apply %[[V11]](%[[V8]]) : $@convention(c) (@convention(block) (@in_guaranteed NonTrivial) -> ()) -> () +// CHECK: destroy_value %[[V8]] : $@convention(block) (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V12:.*]] = tuple () +// CHECK: return %[[V12]] : $() + +// CHECK: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$sSo10NonTrivialVIegn_ABIeyBn_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), @in_guaranteed NonTrivial) -> () { +// CHECK: bb0(%[[V0:.*]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), %[[V1:.*]] : $*NonTrivial): +// CHECK: %[[V2:.*]] = project_block_storage %[[V0]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V3:.*]] = load [copy] %[[V2]] : $*@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V4:.*]] = begin_borrow %[[V3]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V7:.*]] = apply %[[V4]](%[[V1]]) : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: end_borrow %[[V4]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V8:.*]] = tuple () +// CHECK: destroy_value %[[V3]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: return %[[V8]] : $() + +// NonTrivial is destroyed by the caller. +public func testClosureToBlock() { + cfunc({NonTrivial in}) +} + +// CHECK: sil [ossa] @$s4main20testClosureToFuncPtryyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = function_ref @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_To : $@convention(c) (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V1:.*]] = enum $Optional<@convention(c) (@in_guaranteed NonTrivial) -> ()>, #Optional.some!enumelt, %[[V0]] : $@convention(c) (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V2:.*]] = function_ref @_Z6cfunc2PFv10NonTrivialE : $@convention(c) (Optional<@convention(c) (@in_guaranteed NonTrivial) -> ()>) -> () +// CHECK: %[[V3:.*]] = apply %[[V2]](%[[V1]]) : $@convention(c) (Optional<@convention(c) (@in_guaranteed NonTrivial) -> ()>) -> () +// CHECK: %[[V4:.*]] = tuple () +// CHECK: return %[[V4]] : $() + +// CHECK: sil private [thunk] [ossa] @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_To : $@convention(c) (@in_guaranteed NonTrivial) -> () { +// CHECK: bb0(%[[V0:.*]] : $*NonTrivial): +// CHECK: %[[V1:.*]] = alloc_stack $NonTrivial +// CHECK: copy_addr %[[V0]] to [init] %[[V1]] : $*NonTrivial +// CHECK: %[[V3:.*]] = function_ref @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_ : $@convention(thin) (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V4:.*]] = apply %[[V3]](%[[V1]]) : $@convention(thin) (@in_guaranteed NonTrivial) -> () +// CHECK: destroy_addr %[[V1]] : $*NonTrivial +// CHECK: dealloc_stack %[[V1]] : $*NonTrivial +// CHECK: return %[[V4]] : $() + +public func testClosureToFuncPtr() { + cfunc2({N in}) +} diff --git a/test/Interop/Cxx/class/closure-thunk-executable-macosx.swift b/test/Interop/Cxx/class/closure-thunk-executable-macosx.swift new file mode 100644 index 0000000000000..bf57b025672f3 --- /dev/null +++ b/test/Interop/Cxx/class/closure-thunk-executable-macosx.swift @@ -0,0 +1,19 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -cxx-interoperability-mode=default) +// +// REQUIRES: executable_test +// REQUIRES: OS=macosx + +import StdlibUnittest +import Closure + +var ClosureTestSuite = TestSuite("Closure") + +ClosureTestSuite.test("ConvertToBlock") { + cfunc({NonTrivial in}) +} + +ClosureTestSuite.test("ConvertToBlockARCWeak") { + cfuncARCWeak({ARCWeak in}) +} + +runAllTests() diff --git a/test/Interop/Cxx/class/closure-thunk-executable.swift b/test/Interop/Cxx/class/closure-thunk-executable.swift index bb5d8285df8a5..7c23c2443a12a 100644 --- a/test/Interop/Cxx/class/closure-thunk-executable.swift +++ b/test/Interop/Cxx/class/closure-thunk-executable.swift @@ -2,10 +2,6 @@ // // REQUIRES: executable_test -// The test is enabled only on windows until https://github.com/apple/swift/pull/73019 -// is fixed. -// REQUIRES: OS=windows-msvc - import StdlibUnittest import Closure diff --git a/test/Interop/Cxx/class/closure-thunk-macosx.swift b/test/Interop/Cxx/class/closure-thunk-macosx.swift new file mode 100644 index 0000000000000..656c6ca6238f6 --- /dev/null +++ b/test/Interop/Cxx/class/closure-thunk-macosx.swift @@ -0,0 +1,92 @@ +// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-silgen %s | %FileCheck --dump-input-filter=all %s + +// REQUIRES: OS=macosx + +import Closure + +// CHECK: sil [ossa] @$s4main18testClosureToBlockyyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = function_ref @$s4main18testClosureToBlockyyFySo10NonTrivialVcfU_ : $@convention(thin) (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V1:.*]] = thin_to_thick_function %[[V0]] : $@convention(thin) (@in_guaranteed NonTrivial) -> () to $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V2:.*]] = alloc_stack $@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V3:.*]] = project_block_storage %[[V2]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: store %[[V1]] to [trivial] %[[V3]] : $*@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V7:.*]] = function_ref @$sSo10NonTrivialVIegn_ABIeyBC_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), @in_cxx NonTrivial) -> () +// CHECK: %[[V6:.*]] = init_block_storage_header %[[V2]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), invoke %[[V7]] : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), @in_cxx NonTrivial) -> (), type $@convention(block) (@in_cxx NonTrivial) -> () +// CHECK: %[[V8:.*]] = copy_block %[[V6]] : $@convention(block) (@in_cxx NonTrivial) -> () +// CHECK: dealloc_stack %[[V2]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V11:.*]] = function_ref @_Z5cfuncU13block_pointerFv10NonTrivialE : $@convention(c) (@convention(block) (@in_cxx NonTrivial) -> ()) -> () +// CHECK: apply %[[V11]](%[[V8]]) : $@convention(c) (@convention(block) (@in_cxx NonTrivial) -> ()) -> () +// CHECK: destroy_value %[[V8]] : $@convention(block) (@in_cxx NonTrivial) -> () +// CHECK: %[[V12:.*]] = tuple () +// CHECK: return %[[V12]] : $() + +// CHECK: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$sSo10NonTrivialVIegn_ABIeyBC_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), @in_cxx NonTrivial) -> () { +// CHECK: bb0(%[[V0:.*]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), %[[V1:.*]] : $*NonTrivial): +// CHECK: %[[V2:.*]] = project_block_storage %[[V0]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V3:.*]] = load [copy] %[[V2]] : $*@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V4:.*]] = begin_borrow %[[V3]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V7:.*]] = apply %[[V4]](%[[V1]]) : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: end_borrow %[[V4]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V8:.*]] = tuple () +// CHECK: destroy_value %[[V3]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: return %[[V8]] : $() + +// NonTrivial is destroyed by the caller. +public func testClosureToBlock() { + cfunc({NonTrivial in}) +} + +// CHECK: sil [ossa] @$s4main25testClosureToBlockARCWeakyyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = function_ref @$s4main25testClosureToBlockARCWeakyyFySo0F0VcfU_ : $@convention(thin) (@in_guaranteed ARCWeak) -> () +// CHECK: %[[V1:.*]] = thin_to_thick_function %[[V0]] : $@convention(thin) (@in_guaranteed ARCWeak) -> () to $@callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: %[[V2:.*]] = alloc_stack $@block_storage @callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: %[[V3:.*]] = project_block_storage %[[V2]] : $*@block_storage @callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: store %[[V1]] to [trivial] %[[V3]] : $*@callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: %[[V7:.*]] = function_ref @$sSo7ARCWeakVIegn_ABIeyBi_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed ARCWeak) -> (), @in ARCWeak) -> () +// CHECK: %[[V6:.*]] = init_block_storage_header %[[V2]] : $*@block_storage @callee_guaranteed (@in_guaranteed ARCWeak) -> (), invoke %[[V7]] : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed ARCWeak) -> (), @in ARCWeak) -> (), type $@convention(block) (@in ARCWeak) -> () +// CHECK: %[[V8:.*]] = copy_block %[[V6]] : $@convention(block) (@in ARCWeak) -> () +// CHECK: dealloc_stack %[[V2]] : $*@block_storage @callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: %[[V11:.*]] = function_ref @_Z12cfuncARCWeakU13block_pointerFv7ARCWeakE : $@convention(c) (@convention(block) (@in ARCWeak) -> ()) -> () +// CHECK: apply %[[V11]](%[[V8]]) : $@convention(c) (@convention(block) (@in ARCWeak) -> ()) -> () +// CHECK: destroy_value %[[V8]] : $@convention(block) (@in ARCWeak) -> () +// CHECK: %[[V12:.*]] = tuple () +// CHECK: return %[[V12]] : $() + +// CHECK: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$sSo7ARCWeakVIegn_ABIeyBi_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed ARCWeak) -> (), @in ARCWeak) -> () { +// CHECK: bb0(%[[V0:.*]] : $*@block_storage @callee_guaranteed (@in_guaranteed ARCWeak) -> (), %[[V1:.*]] : $*ARCWeak): +// CHECK: %[[V2:.*]] = project_block_storage %[[V0]] : $*@block_storage @callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: %[[V3:.*]] = load [copy] %[[V2]] : $*@callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: %[[V4:.*]] = begin_borrow %[[V3]] : $@callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: %[[V7:.*]] = apply %[[V4]](%[[V1]]) : $@callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: end_borrow %[[V4]] : $@callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: %[[V8:.*]] = tuple () +// CHECK: destroy_addr %[[V1]] : $*ARCWeak +// CHECK: destroy_value %[[V3]] : $@callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: return %[[V8]] : $() + +// ARCWeak is destroyed by the callee. +public func testClosureToBlockARCWeak() { + cfuncARCWeak({ARCWeak in}) +} + +// CHECK: sil [ossa] @$s4main20testClosureToFuncPtryyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = function_ref @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_To : $@convention(c) (@in_cxx NonTrivial) -> () +// CHECK: %[[V1:.*]] = enum $Optional<@convention(c) (@in_cxx NonTrivial) -> ()>, #Optional.some!enumelt, %[[V0]] : $@convention(c) (@in_cxx NonTrivial) -> () +// CHECK: %[[V2:.*]] = function_ref @_Z6cfunc2PFv10NonTrivialE : $@convention(c) (Optional<@convention(c) (@in_cxx NonTrivial) -> ()>) -> () +// CHECK: %[[V3:.*]] = apply %[[V2]](%[[V1]]) : $@convention(c) (Optional<@convention(c) (@in_cxx NonTrivial) -> ()>) -> () +// CHECK: %[[V4:.*]] = tuple () +// CHECK: return %[[V4]] : $() + +// CHECK: sil private [thunk] [ossa] @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_To : $@convention(c) (@in_cxx NonTrivial) -> () { +// CHECK: bb0(%[[V0:.*]] : $*NonTrivial): +// CHECK: %[[V1:.*]] = alloc_stack $NonTrivial +// CHECK: copy_addr %[[V0]] to [init] %[[V1]] : $*NonTrivial +// CHECK: %[[V3:.*]] = function_ref @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_ : $@convention(thin) (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V4:.*]] = apply %[[V3]](%[[V1]]) : $@convention(thin) (@in_guaranteed NonTrivial) -> () +// CHECK: destroy_addr %[[V1]] : $*NonTrivial +// CHECK: dealloc_stack %[[V1]] : $*NonTrivial +// CHECK: return %[[V4]] : $() + +public func testClosureToFuncPtr() { + cfunc2({N in}) +} diff --git a/test/Interop/Cxx/class/closure-thunk-windows.swift b/test/Interop/Cxx/class/closure-thunk-windows.swift new file mode 100644 index 0000000000000..deca203a24142 --- /dev/null +++ b/test/Interop/Cxx/class/closure-thunk-windows.swift @@ -0,0 +1,57 @@ +// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-silgen %s | %FileCheck --dump-input-filter=all %s + +// REQUIRES: OS=windows-msvc + +import Closure + +// CHECK: sil [ossa] @$s4main18testClosureToBlockyyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = function_ref @$s4main18testClosureToBlockyyFySo10NonTrivialVcfU_ : $@convention(thin) (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V1:.*]] = thin_to_thick_function %[[V0]] : $@convention(thin) (@in_guaranteed NonTrivial) -> () to $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V2:.*]] = alloc_stack $@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V3:.*]] = project_block_storage %[[V2]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: store %[[V1]] to [trivial] %[[V3]] : $*@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V7:.*]] = function_ref @$sSo10NonTrivialVIegn_ABIeyBi_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), @in NonTrivial) -> () +// CHECK: %[[V6:.*]] = init_block_storage_header %[[V2]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), invoke %[[V7]] : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), @in NonTrivial) -> (), type $@convention(block) (@in NonTrivial) -> () +// CHECK: %[[V8:.*]] = copy_block %[[V6]] : $@convention(block) (@in NonTrivial) -> () +// CHECK: dealloc_stack %[[V2]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V11:.*]] = function_ref @?cfunc@@YAXP_EAXUNonTrivial@@@Z@Z : $@convention(c) (@convention(block) (@in NonTrivial) -> ()) -> () +// CHECK: apply %[[V11]](%[[V8]]) : $@convention(c) (@convention(block) (@in NonTrivial) -> ()) -> () +// CHECK: destroy_value %[[V8]] : $@convention(block) (@in NonTrivial) -> () +// CHECK: %[[V12:.*]] = tuple () +// CHECK: return %[[V12]] : $() + +// CHECK: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$sSo10NonTrivialVIegn_ABIeyBi_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), @in NonTrivial) -> () { +// CHECK: bb0(%[[V0:.*]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), %[[V1:.*]] : $*NonTrivial): +// CHECK: %[[V2:.*]] = project_block_storage %[[V0]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V3:.*]] = load [copy] %[[V2]] : $*@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V4:.*]] = begin_borrow %[[V3]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V7:.*]] = apply %[[V4]](%[[V1]]) : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: end_borrow %[[V4]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V8:.*]] = tuple () +// CHECK: dealloc_addr %[[V1]] : $*NonTrivial +// CHECK: destroy_value %[[V3]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: return %[[V8]] : $() + +// NonTrivial is destroyed by the caller. +public func testClosureToBlock() { + cfunc({NonTrivial in}) +} + +// CHECK: sil [ossa] @$s4main20testClosureToFuncPtryyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = function_ref @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_To : $@convention(c) (@in NonTrivial) -> () +// CHECK: %[[V1:.*]] = enum $Optional<@convention(c) (@in NonTrivial) -> ()>, #Optional.some!enumelt, %[[V0]] : $@convention(c) (@in NonTrivial) -> () +// CHECK: %[[V2:.*]] = function_ref @?cfunc2@@YAXP6AXUNonTrivial@@@Z@Z : $@convention(c) (Optional<@convention(c) (@in NonTrivial) -> ()>) -> () +// CHECK: %[[V3:.*]] = apply %[[V2]](%[[V1]]) : $@convention(c) (Optional<@convention(c) (@in NonTrivial) -> ()>) -> () +// CHECK: %[[V4:.*]] = tuple () +// CHECK: return %[[V4]] : $() + +// CHECK: sil private [thunk] [ossa] @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_To : $@convention(c) (@in NonTrivial) -> () { +// CHECK: bb0(%[[V0:.*]] : $*NonTrivial): +// CHECK: %[[V3:.*]] = function_ref @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_ : $@convention(thin) (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V4:.*]] = apply %[[V3]](%[[V0]]) : $@convention(thin) (@in_guaranteed NonTrivial) -> () +// CHECK: destroy_addr %[[V0]] : $*NonTrivial +// CHECK: return %[[V4]] : $() + +public func testClosureToFuncPtr() { + cfunc2({N in}) +} diff --git a/test/Interop/Cxx/class/closure-thunk.swift b/test/Interop/Cxx/class/closure-thunk.swift index f1fd614d58f49..e69de29bb2d1d 100644 --- a/test/Interop/Cxx/class/closure-thunk.swift +++ b/test/Interop/Cxx/class/closure-thunk.swift @@ -1,21 +0,0 @@ -// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-silgen %s | %FileCheck %s - -import Closure - -// CHECK: sil [ossa] @$s4main20testClosureToFuncPtryyF : $@convention(thin) () -> () { -// CHECK: %[[V0:.*]] = function_ref @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_To : $@convention(c) (@in NonTrivial) -> () -// CHECK: %[[V1:.*]] = enum $Optional<@convention(c) (@in NonTrivial) -> ()>, #Optional.some!enumelt, %[[V0]] : $@convention(c) (@in NonTrivial) -> () -// CHECK: %[[V2:.*]] = function_ref @{{.*}}cfunc2{{.*}}NonTrivial{{.*}} : $@convention(c) (Optional<@convention(c) (@in NonTrivial) -> ()>) -> () -// CHECK: %[[V3:.*]] = apply %[[V2]](%[[V1]]) : $@convention(c) (Optional<@convention(c) (@in NonTrivial) -> ()>) -> () - -// CHECK: sil private [ossa] @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_ : $@convention(thin) (@in_guaranteed NonTrivial) -> () { - -// CHECK: sil private [thunk] [ossa] @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_To : $@convention(c) (@in NonTrivial) -> () { -// CHECK: bb0(%[[V0:.*]] : $*NonTrivial): -// CHECK: %[[V1:.*]] = function_ref @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_ : $@convention(thin) (@in_guaranteed NonTrivial) -> () -// CHECK: %[[V2:.*]] = apply %[[V1]](%[[V0]]) : $@convention(thin) (@in_guaranteed NonTrivial) -> () -// CHECK: destroy_addr %[[V0]] : $*NonTrivial - -public func testClosureToFuncPtr() { - cfunc2({N in}) -} diff --git a/test/Interop/Cxx/class/function-call-macosx.swift b/test/Interop/Cxx/class/function-call-macosx.swift new file mode 100644 index 0000000000000..3aee5adb5d750 --- /dev/null +++ b/test/Interop/Cxx/class/function-call-macosx.swift @@ -0,0 +1,34 @@ +// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-silgen %s | %FileCheck --dump-input-filter=all %s + +// REQUIRES: OS=macosx + +import Closure + +// CHECK: sil [ossa] @$s4main11testARCWeakyyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = alloc_stack $ARCWeak +// CHECK: %[[V2:.*]] = function_ref @_ZN7ARCWeakC1Ev : $@convention(c) () -> @out ARCWeak +// CHECK: %[[V3:.*]] = apply %[[V2]](%[[V0]]) : $@convention(c) () -> @out ARCWeak +// CHECK: %[[V4:.*]] = function_ref @_Z12cfuncARCWeak7ARCWeak : $@convention(c) (@in ARCWeak) -> () +// CHECK: %[[V7:.*]] = apply %[[V4]](%[[V0]]) : $@convention(c) (@in ARCWeak) -> () +// CHECK-NOT: destroy_addr +// CHECK: dealloc_stack %[[V0]] : $*ARCWeak + +public func testARCWeak() { + cfuncARCWeak(ARCWeak()); +} + +// CHECK: sil [ossa] @$s4main26testARCWeakFunctionPointeryyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = function_ref @_Z9getFnPtr2v : $@convention(c) () -> @convention(c) (@in ARCWeak) -> () +// CHECK: %[[V1:.*]] = apply %[[V0]]() : $@convention(c) () -> @convention(c) (@in ARCWeak) -> () +// CHECK: %[[V3:.*]] = alloc_stack $ARCWeak +// CHECK: %[[V6:.*]] = function_ref @_ZN7ARCWeakC1Ev : $@convention(c) () -> @out ARCWeak +// CHECK: apply %[[V6]](%[[V3]]) : $@convention(c) () -> @out ARCWeak +// CHECK: apply %[[V1]](%[[V3]]) : $@convention(c) (@in ARCWeak) -> () +// CHECK-NEXT: dealloc_stack %[[V3]] : $*ARCWeak +// CHECK-NEXT: %[[V9:.*]] = tuple () +// CHECK-NEXT: return %[[V9]] : $() + +public func testARCWeakFunctionPointer() { + let f = getFnPtr2() + f(ARCWeak()) +} diff --git a/test/Interop/Cxx/class/function-call-windows.swift b/test/Interop/Cxx/class/function-call-windows.swift new file mode 100644 index 0000000000000..68b514693937a --- /dev/null +++ b/test/Interop/Cxx/class/function-call-windows.swift @@ -0,0 +1,17 @@ +// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-silgen %s | %FileCheck --dump-input-filter=all %s + +// REQUIRES: OS=windows-msvc + +import Closure + +// CHECK: sil [ossa] @$s4main14testNonTrivialyyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = alloc_stack $NonTrivial +// CHECK: %[[V2:.*]] = function_ref @??0NonTrivial@@QEAA@XZ : $@convention(c) () -> @out NonTrivial +// CHECK: %[[V3:.*]] = apply %[[V2]](%[[V0]]) : $@convention(c) () -> @out NonTrivial +// CHECK: %[[V4:.*]] = function_ref @?cfunc@@YAXUNonTrivial@@@Z : $@convention(c) (@in NonTrivial) -> () +// CHECK: %[[V7:.*]] = apply %[[V4]](%[[V0]]) : $@convention(c) (@in NonTrivial) -> () +// CHECK: dealloc_stack %[[V0]] : $*NonTrivial + +public func testNonTrivial() { + cfunc(NonTrivial()); +} diff --git a/test/Interop/Cxx/class/function-call.swift b/test/Interop/Cxx/class/function-call.swift new file mode 100644 index 0000000000000..9a40f2ac520f9 --- /dev/null +++ b/test/Interop/Cxx/class/function-call.swift @@ -0,0 +1,33 @@ +// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-silgen %s | %FileCheck --dump-input-filter=all %s + +// REQUIRES: OS=macosx || OS=linux-android + +import Closure + +// CHECK: sil [ossa] @$s4main14testNonTrivialyyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = alloc_stack $NonTrivial +// CHECK: %[[V2:.*]] = function_ref @_ZN10NonTrivialC1Ev : $@convention(c) () -> @out NonTrivial +// CHECK: %[[V3:.*]] = apply %[[V2]](%[[V0]]) : $@convention(c) () -> @out NonTrivial +// CHECK: %[[V4:.*]] = function_ref @_Z5cfunc10NonTrivial : $@convention(c) (@in_cxx NonTrivial) -> () +// CHECK: %[[V7:.*]] = apply %[[V4]](%[[V0]]) : $@convention(c) (@in_cxx NonTrivial) -> () +// CHECK: destroy_addr %[[V0]] : $*NonTrivial +// CHECK: dealloc_stack %[[V0]] : $*NonTrivial + +public func testNonTrivial() { + cfunc(NonTrivial()); +} + +// CHECK: sil [ossa] @$s4main29testNonTrivialFunctionPointeryyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = function_ref @_Z8getFnPtrv : $@convention(c) () -> @convention(c) (@in_cxx NonTrivial) -> () +// CHECK: %[[V1:.*]] = apply %[[V0]]() : $@convention(c) () -> @convention(c) (@in_cxx NonTrivial) -> () +// CHECK: %[[V3:.*]] = alloc_stack $NonTrivial +// CHECK: %[[V7:.*]] = function_ref @_ZN10NonTrivialC1Ev : $@convention(c) () -> @out NonTrivial +// CHECK: apply %[[V7]](%[[V3]]) : $@convention(c) () -> @out NonTrivial +// CHECK: apply %[[V1]](%[[V3]]) : $@convention(c) (@in_cxx NonTrivial) -> () +// CHECK: destroy_addr %[[V3]] : $*NonTrivial +// CHECK: dealloc_stack %[[V3]] : $*NonTrivial + +public func testNonTrivialFunctionPointer() { + let f = getFnPtr() + f(NonTrivial()) +} diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-silgen-windows.swift b/test/Interop/Cxx/class/type-classification-non-trivial-silgen-windows.swift new file mode 100644 index 0000000000000..d88bf4235f1da --- /dev/null +++ b/test/Interop/Cxx/class/type-classification-non-trivial-silgen-windows.swift @@ -0,0 +1,176 @@ +// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-silgen %s | %FileCheck --dump-input-filter=all %s + +// REQUIRES: OS=windows-msvc + +import TypeClassification + +// Make sure that "StructWithDestructor" is marked as non-trivial by checking for a +// "destroy_addr". +// CHECK-LABEL: sil [ossa] @$s4main24testStructWithDestructoryyF +// CHECK: [[AS:%.*]] = alloc_stack [lexical] [var_decl] $StructWithDestructor +// CHECK: [[FN:%.*]] = function_ref @{{_ZN20StructWithDestructorC1Ev|\?\?0StructWithDestructor@@QEAA@XZ}} : $@convention(c) () -> @out StructWithDestructor +// CHECK: apply [[FN]]([[AS]]) : $@convention(c) () -> @out StructWithDestructor +// CHECK: destroy_addr [[AS]] +// CHECK: dealloc_stack %0 : $*StructWithDestructor +// CHECK-LABEL: end sil function '$s4main24testStructWithDestructoryyF' + +// CHECK-LABEL: sil [clang StructWithDestructor.init] @{{_ZN20StructWithDestructorC1Ev|\?\?0StructWithDestructor@@QEAA@XZ}} : $@convention(c) () -> @out StructWithDestructor +public func testStructWithDestructor() { + let d = StructWithDestructor() +} + +// Make sure that "HasMemberWithDestructor" is marked as non-trivial by checking +// for a "destroy_addr". +// CHECK-LABEL: sil [ossa] @$s4main33testStructWithSubobjectDestructoryyF : $@convention(thin) () -> () +// CHECK: [[AS:%.*]] = alloc_stack [lexical] [var_decl] $StructWithSubobjectDestructor +// CHECK: [[FN:%.*]] = function_ref @{{_ZN29StructWithSubobjectDestructorC1Ev|\?\?0StructWithSubobjectDestructor@@QEAA@XZ}} : $@convention(c) () -> @out StructWithSubobjectDestructor +// CHECK: apply [[FN]]([[AS]]) : $@convention(c) () -> @out StructWithSubobjectDestructor +// CHECK: destroy_addr [[AS]] +// CHECK-LABEL: end sil function '$s4main33testStructWithSubobjectDestructoryyF' + +// CHECK-LABEL: sil [clang StructWithSubobjectDestructor.init] @{{_ZN29StructWithSubobjectDestructorC1Ev|\?\?0StructWithSubobjectDestructor@@QEAA@XZ}} : $@convention(c) () -> @out StructWithSubobjectDestructor +public func testStructWithSubobjectDestructor() { + let d = StructWithSubobjectDestructor() +} + +// CHECK-LABEL: sil [ossa] @$s4main37testStructWithCopyConstructorAndValueSbyF +// CHECK: [[AS:%.*]] = alloc_stack [lexical] [var_decl] $StructWithCopyConstructorAndValue +// CHECK: [[FN:%.*]] = function_ref @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], %{{.*}}) : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue +// CHECK: [[OBJ_VAL_ADDR:%.*]] = struct_element_addr [[AS]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_VAL:%.*]] = load [trivial] [[OBJ_VAL_ADDR]] : $*Int32 +// CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 +// CHECK: [[MAKE_INT_FN:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT_42:%.*]] = apply [[MAKE_INT_FN]]([[IL_42]], %{{.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[CMP_FN:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[CMP_FN]]([[OBJ_VAL]], [[INT_42]], %{{.*}}) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: destroy_addr [[AS]] : $*StructWithCopyConstructorAndValue +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main37testStructWithCopyConstructorAndValueSbyF' + +// CHECK-LABEL: sil [clang StructWithCopyConstructorAndValue.init] @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue +public func testStructWithCopyConstructorAndValue() -> Bool { + let obj = StructWithCopyConstructorAndValue(42) + return obj.value == 42 +} + +// CHECK-LABEL: sil [ossa] @$s4main46testStructWithSubobjectCopyConstructorAndValueSbyF : $@convention(thin) () -> Bool +// CHECK: [[MEMBER_0:%.*]] = alloc_stack [lexical] [var_decl] $StructWithCopyConstructorAndValue +// CHECK: [[MAKE_MEMBER_FN:%.*]] = function_ref @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[MAKE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}) : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue +// CHECK: [[AS:%.*]] = alloc_stack [lexical] [var_decl] $StructWithSubobjectCopyConstructorAndValue +// CHECK: [[META:%.*]] = metatype $@thin StructWithSubobjectCopyConstructorAndValue.Type +// CHECK: [[MEMBER_1:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr %0 to [init] [[MEMBER_1]] : $*StructWithCopyConstructorAndValue +// CHECK: [[FN:%.*]] = function_ref @$sSo42StructWithSubobjectCopyConstructorAndValueV6memberABSo0abdefG0V_tcfC : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithSubobjectCopyConstructorAndValue.Type) -> @out StructWithSubobjectCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], [[MEMBER_1]], [[META]]) : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithSubobjectCopyConstructorAndValue.Type) -> @out StructWithSubobjectCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER:%.*]] = struct_element_addr [[AS]] : $*StructWithSubobjectCopyConstructorAndValue, #StructWithSubobjectCopyConstructorAndValue.member +// CHECK: [[MEMBER_2:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[OBJ_MEMBER]] to [init] [[MEMBER_2]] : $*StructWithCopyConstructorAndValue +// CHECK: [[OBJ_VALUE_ADDR:%.*]] = struct_element_addr [[MEMBER_2]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_VALUE:%.*]] = load [trivial] [[OBJ_VALUE_ADDR]] : $*Int32 +// CHECK: [[MAKE_INT:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT_42:%.*]] = apply [[MAKE_INT]]({{.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[ICMP:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[ICMP]]([[OBJ_VALUE]], [[INT_42]], %{{.*}}) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main46testStructWithSubobjectCopyConstructorAndValueSbyF' +public func testStructWithSubobjectCopyConstructorAndValue() -> Bool { + let member = StructWithCopyConstructorAndValue(42) + let obj = StructWithSubobjectCopyConstructorAndValue(member: member) + return obj.member.value == 42 +} + +// StructWithSubobjectCopyConstructorAndValue.init(member:) +// CHECK-LABEL: sil shared [transparent] [serialized] [ossa] @$sSo42StructWithSubobjectCopyConstructorAndValueV6memberABSo0abdefG0V_tcfC : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithSubobjectCopyConstructorAndValue.Type) -> @out StructWithSubobjectCopyConstructorAndValue +// CHECK: [[MEMBER:%.*]] = struct_element_addr %0 : $*StructWithSubobjectCopyConstructorAndValue, #StructWithSubobjectCopyConstructorAndValue.member +// CHECK: copy_addr [take] %1 to [init] [[MEMBER]] : $*StructWithCopyConstructorAndValue +// CHECK-LABEL: end sil function '$sSo42StructWithSubobjectCopyConstructorAndValueV6memberABSo0abdefG0V_tcfC' + +// testStructWithCopyConstructorAndSubobjectCopyConstructorAndValue() +// CHECK-LABEL: sil [ossa] @$s4main041testStructWithCopyConstructorAndSubobjectefG5ValueSbyF : $@convention(thin) () -> Bool +// CHECK: [[MEMBER_0:%.*]] = alloc_stack [lexical] [var_decl] $StructWithCopyConstructorAndValue +// CHECK: [[CREATE_MEMBER_FN:%.*]] = function_ref @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[CREATE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}) : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue +// CHECK: [[AS:%.*]] = alloc_stack [lexical] [var_decl] $StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: [[MEMBER_1:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[MEMBER_0]] to [init] [[MEMBER_1]] : $*StructWithCopyConstructorAndValue +// CHECK: [[FN:%.*]] = function_ref @{{_ZN60StructWithCopyConstructorAndSubobjectCopyConstructorAndValueC1E33StructWithCopyConstructorAndValue|\?\?0StructWithCopyConstructorAndSubobjectCopyConstructorAndValue@@QEAA@UStructWithCopyConstructorAndValue@@@Z}} : $@convention(c) (@in StructWithCopyConstructorAndValue) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], [[MEMBER_1]]) : $@convention(c) (@in StructWithCopyConstructorAndValue) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER_ADDR:%.*]] = struct_element_addr [[AS]] : $*StructWithCopyConstructorAndSubobjectCopyConstructorAndValue, #StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.member +// CHECK: [[MEMBER_2:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[OBJ_MEMBER_ADDR]] to [init] [[MEMBER_2]] : $*StructWithCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER_VALUE_ADDR:%.*]] = struct_element_addr [[MEMBER_2]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_MEMBER_VALUE:%.*]] = load [trivial] [[OBJ_MEMBER_VALUE_ADDR]] : $*Int32 +// CHECK: [[ICMP:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[ICMP]]([[OBJ_MEMBER_VALUE]], %{{.*}}) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main041testStructWithCopyConstructorAndSubobjectefG5ValueSbyF' +public func testStructWithCopyConstructorAndSubobjectCopyConstructorAndValue() +-> Bool { + let member = StructWithCopyConstructorAndValue(42) + let obj = StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( + member + ) + return obj.member.value == 42 +} + +// CHECK-LABEL: sil [ossa] @$s4main4test3objSbSo33StructWithCopyConstructorAndValueV_tF : $@convention(thin) (@in_guaranteed StructWithCopyConstructorAndValue) -> Bool +// CHECK: [[META_1:%.*]] = metatype $@thin Int32.Type +// CHECK: [[OBJ_VAL_ADDR:%.*]] = struct_element_addr %0 : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_VAL:%.*]] = load [trivial] [[OBJ_VAL_ADDR]] : $*Int32 +// CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 +// CHECK: [[META_2:%.*]] = metatype $@thin Int32.Type +// CHECK: [[FN:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT:%.*]] = apply [[FN]]([[IL_42]], [[META_2]]) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[FN_2:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[FN_2]]([[OBJ_VAL]], [[INT]], [[META_1]]) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main4test3objSbSo33StructWithCopyConstructorAndValueV_tF' +public func test(obj: StructWithCopyConstructorAndValue) -> Bool { + return obj.value == 42 +} + +// CHECK-LABEL: sil [ossa] @$s4main4test3objSbSo42StructWithSubobjectCopyConstructorAndValueV_tF : $@convention(thin) (@in_guaranteed StructWithSubobjectCopyConstructorAndValue) -> Bool +// CHECK: [[INT_META:%.*]] = metatype $@thin Int32.Type +// CHECK: [[OBJ_MEMBER:%.*]] = struct_element_addr %0 : $*StructWithSubobjectCopyConstructorAndValue, #StructWithSubobjectCopyConstructorAndValue.member +// CHECK: [[MEMBER_TMP:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[OBJ_MEMBER]] to [init] [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER_VALUE_ADDR:%.*]] = struct_element_addr [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_MEMBER_VALUE:%.*]] = load [trivial] [[OBJ_MEMBER_VALUE_ADDR]] : $*Int32 +// CHECK: destroy_addr [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 +// CHECK: [[INT_META_2:%.*]] = metatype $@thin Int32.Type +// CHECK: [[MAKE_INT_FN:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT_42:%.*]] = apply [[MAKE_INT_FN]]([[IL_42]], [[INT_META_2]]) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[FN:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[FN]]([[OBJ_MEMBER_VALUE]], [[INT_42]], [[INT_META]]) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: dealloc_stack [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main4test3objSbSo42StructWithSubobjectCopyConstructorAndValueV_tF' +public func test(obj: StructWithSubobjectCopyConstructorAndValue) -> Bool { + return obj.member.value == 42 +} + +// CHECK-LABEL: sil [ossa] @$s4main4test3objSbSo037StructWithCopyConstructorAndSubobjectfgH5ValueV_tF +// CHECK: [[META_INT_1:%.*]] = metatype $@thin Int32.Type +// CHECK: [[OBJ_MEMBER:%.*]] = struct_element_addr %0 : $*StructWithCopyConstructorAndSubobjectCopyConstructorAndValue, #StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.member +// CHECK: [[MEMBER_TMP:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[OBJ_MEMBER]] to [init] [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER_VAL_ADDR:%.*]] = struct_element_addr [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_MEMBER_VAL:%.*]] = load [trivial] [[OBJ_MEMBER_VAL_ADDR]] : $*Int32 +// CHECK: destroy_addr [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 +// CHECK: [[META_INT_2:%.*]] = metatype $@thin Int32.Type +// CHECK: [[MAKE_INT_FN:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT_42:%.*]] = apply [[MAKE_INT_FN]]([[IL_42]], [[META_INT_2]]) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[ICMP_FN:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[ICMP_FN]]([[OBJ_MEMBER_VAL]], [[INT_42]], [[META_INT_1]]) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: dealloc_stack [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main4test3objSbSo037StructWithCopyConstructorAndSubobjectfgH5ValueV_tF' +public func test( + obj: StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +) -> Bool { + return obj.member.value == 42 +} diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift b/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift index cc0f96adb0f8d..bfdc06aa119f9 100644 --- a/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift +++ b/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift @@ -1,4 +1,6 @@ -// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-silgen %s | %FileCheck %s +// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-silgen %s | %FileCheck --dump-input-filter=all %s + +// REQUIRES: OS=macosx || OS=linux-android import TypeClassification @@ -93,8 +95,8 @@ public func testStructWithSubobjectCopyConstructorAndValue() -> Bool { // CHECK: [[AS:%.*]] = alloc_stack [lexical] [var_decl] $StructWithCopyConstructorAndSubobjectCopyConstructorAndValue // CHECK: [[MEMBER_1:%.*]] = alloc_stack $StructWithCopyConstructorAndValue // CHECK: copy_addr [[MEMBER_0]] to [init] [[MEMBER_1]] : $*StructWithCopyConstructorAndValue -// CHECK: [[FN:%.*]] = function_ref @{{_ZN60StructWithCopyConstructorAndSubobjectCopyConstructorAndValueC1E33StructWithCopyConstructorAndValue|\?\?0StructWithCopyConstructorAndSubobjectCopyConstructorAndValue@@QEAA@UStructWithCopyConstructorAndValue@@@Z}} : $@convention(c) (@in StructWithCopyConstructorAndValue) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue -// CHECK: apply [[FN]]([[AS]], [[MEMBER_1]]) : $@convention(c) (@in StructWithCopyConstructorAndValue) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: [[FN:%.*]] = function_ref @{{_ZN60StructWithCopyConstructorAndSubobjectCopyConstructorAndValueC1E33StructWithCopyConstructorAndValue|\?\?0StructWithCopyConstructorAndSubobjectCopyConstructorAndValue@@QEAA@UStructWithCopyConstructorAndValue@@@Z}} : $@convention(c) (@in_cxx StructWithCopyConstructorAndValue) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], [[MEMBER_1]]) : $@convention(c) (@in_cxx StructWithCopyConstructorAndValue) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue // CHECK: [[OBJ_MEMBER_ADDR:%.*]] = struct_element_addr [[AS]] : $*StructWithCopyConstructorAndSubobjectCopyConstructorAndValue, #StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.member // CHECK: [[MEMBER_2:%.*]] = alloc_stack $StructWithCopyConstructorAndValue // CHECK: copy_addr [[OBJ_MEMBER_ADDR]] to [init] [[MEMBER_2]] : $*StructWithCopyConstructorAndValue diff --git a/test/Interop/Cxx/objc-correctness/call-to-generated-init-with-nsstring.swift b/test/Interop/Cxx/objc-correctness/call-to-generated-init-with-nsstring.swift index 4d05ccb586db3..51de465f4bb7e 100644 --- a/test/Interop/Cxx/objc-correctness/call-to-generated-init-with-nsstring.swift +++ b/test/Interop/Cxx/objc-correctness/call-to-generated-init-with-nsstring.swift @@ -38,10 +38,10 @@ testSdump() // SIL-NONTRIVIAL: function_ref @_ZNK1S4dumpEv : $@convention(cxx_method) (@in_guaranteed S) -> () // SIL-NONTRIVIAL-NEXT: apply %{{.*}}(%{{.*}}) : $@convention(cxx_method) (@in_guaranteed S) -> () -// SIL-NONTRIVIAL: $@convention(objc_method) (@in S, ClassWithNonTrivialDestructorIvar) -> () -// SIL-NONTRIVIAL-NEXT: apply %{{.*}}(%{{.*}}) : $@convention(objc_method) (@in S, ClassWithNonTrivialDestructorIvar) -> () -// SIL-NONTRIVIAL: function_ref @_Z9takeSFunc1S : $@convention(c) (@in S) -> () -// SIL-NONTRIVIAL-NEXT: apply %{{.*}}(%{{.*}}) : $@convention(c) (@in S) -> () +// SIL-NONTRIVIAL: $@convention(objc_method) (@in_cxx S, ClassWithNonTrivialDestructorIvar) -> () +// SIL-NONTRIVIAL-NEXT: apply %{{.*}}(%{{.*}}) : $@convention(objc_method) (@in_cxx S, ClassWithNonTrivialDestructorIvar) -> () +// SIL-NONTRIVIAL: function_ref @_Z9takeSFunc1S : $@convention(c) (@in_cxx S) -> () +// SIL-NONTRIVIAL-NEXT: apply %{{.*}}(%{{.*}}) : $@convention(c) (@in_cxx S) -> () // IR-TRIVIAL-LABEL: define {{.*}} swiftcc void @"$s4main9testSdumpyyF"()