diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeSideEffects.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeSideEffects.swift index 5fcfff3983cc2..8e22e7179292b 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeSideEffects.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeSideEffects.swift @@ -287,6 +287,8 @@ private struct CollectedEffects { private mutating func addEffects(ofFunctions callees: FunctionArray?, withArguments arguments: Arguments) where Arguments.Element == (calleeArgumentIndex: Int, callerArgument: Value) { + // The argument summary for @in_cxx is insufficient in OSSA because the function body does not contain the + // destroy. But the call is still effectively a release from the caller's perspective. guard let callees = callees else { // We don't know which function(s) are called. globalEffects = .worstEffects diff --git a/SwiftCompilerSources/Sources/SIL/Argument.swift b/SwiftCompilerSources/Sources/SIL/Argument.swift index 4e7f6a34afacb..dda4c040ab181 100644 --- a/SwiftCompilerSources/Sources/SIL/Argument.swift +++ b/SwiftCompilerSources/Sources/SIL/Argument.swift @@ -352,6 +352,12 @@ 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. This corresponds to the parameter-passing convention of the + /// Itanium C++ ABI, which is used ubiquitously on non-Windows targets. + 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. @@ -407,8 +413,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 @@ -417,11 +424,12 @@ public enum ArgumentConvention : CustomStringConvertible { public var isIndirectIn: Bool { switch self { - case .indirectIn, .indirectInGuaranteed, + case .indirectIn, .indirectInGuaranteed, .indirectInCXX, .packOwned, .packGuaranteed: return true case .directOwned, .directUnowned, .directGuaranteed, - .indirectInout, .indirectInoutAliasable, .indirectOut, + .indirectInout, .indirectInoutAliasable, + .indirectOut, .packOut, .packInout: return false } @@ -433,7 +441,7 @@ public enum ArgumentConvention : CustomStringConvertible { return true case .indirectInGuaranteed, .directGuaranteed, .packGuaranteed, .indirectIn, .directOwned, .directUnowned, - .indirectInout, .indirectInoutAliasable, + .indirectInout, .indirectInoutAliasable, .indirectInCXX, .packInout, .packOwned: return false } @@ -444,15 +452,15 @@ 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 } } public var isConsumed: Bool { switch self { - case .indirectIn, .directOwned, .packOwned: + case .indirectIn, .indirectInCXX, .directOwned, .packOwned: return true case .indirectInGuaranteed, .directGuaranteed, .packGuaranteed, .indirectInout, .indirectInoutAliasable, .indirectOut, @@ -467,6 +475,7 @@ public enum ArgumentConvention : CustomStringConvertible { .indirectOut, .indirectInGuaranteed, .indirectInout, + .indirectInCXX, .packOut, .packInout, .packOwned, @@ -491,6 +500,7 @@ public enum ArgumentConvention : CustomStringConvertible { case .indirectIn, .indirectOut, .indirectInGuaranteed, + .indirectInCXX, .directUnowned, .directGuaranteed, .directOwned, @@ -511,6 +521,8 @@ public enum ArgumentConvention : CustomStringConvertible { return "indirectInout" case .indirectInoutAliasable: return "indirectInoutAliasable" + case .indirectInCXX: + return "indirectInCXX" case .indirectOut: return "indirectOut" case .directOwned: @@ -545,6 +557,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 @@ -566,6 +579,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 1fc37541c8ab2..8b59602509a1b 100644 --- a/SwiftCompilerSources/Sources/SIL/FunctionConvention.swift +++ b/SwiftCompilerSources/Sources/SIL/FunctionConvention.swift @@ -171,7 +171,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/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index 630cfe4e890a1..3e10b55976c32 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -867,6 +867,7 @@ mangled in to disambiguate. PARAM-CONVENTION ::= 'l' // indirect inout PARAM-CONVENTION ::= 'b' // indirect inout aliasable PARAM-CONVENTION ::= 'n' // indirect in guaranteed + PARAM-CONVENTION ::= 'X' // indirect in C++ PARAM-CONVENTION ::= 'x' // direct owned PARAM-CONVENTION ::= 'y' // direct unowned PARAM-CONVENTION ::= 'g' // direct guaranteed diff --git a/include/swift/AST/TypeAttr.def b/include/swift/AST/TypeAttr.def index 9fcf98c9d1e31..bcb19e0ae4706 100644 --- a/include/swift/AST/TypeAttr.def +++ b/include/swift/AST/TypeAttr.def @@ -82,6 +82,7 @@ SIMPLE_SIL_TYPE_ATTR(in, In) SIMPLE_SIL_TYPE_ATTR(inout, Inout) SIMPLE_SIL_TYPE_ATTR(inout_aliasable, InoutAliasable) SIMPLE_SIL_TYPE_ATTR(in_guaranteed, InGuaranteed) +SIMPLE_SIL_TYPE_ATTR(in_cxx, InCXX) SIMPLE_SIL_TYPE_ATTR(in_constant, InConstant) SIMPLE_SIL_TYPE_ATTR(pack_owned, PackOwned) SIMPLE_SIL_TYPE_ATTR(pack_guaranteed, PackGuaranteed) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 18f10c8fc035e..a320e4885957a 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -4068,6 +4068,12 @@ 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. This corresponds to the parameter-passing convention of the + /// Itanium C++ ABI, which is used ubiquitously on non-Windows targets. + Indirect_In_CXX, + /// This argument is passed directly. Its type is non-trivial, and the callee /// is responsible for destroying it. Direct_Owned, @@ -4108,6 +4114,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; @@ -4129,7 +4136,8 @@ bool isConsumedParameter(ParameterConvention conv) { case ParameterConvention::Direct_Owned: case ParameterConvention::Pack_Owned: return true; - + case ParameterConvention::Indirect_In_CXX: + return !InCallee; case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: case ParameterConvention::Direct_Unowned: @@ -4160,7 +4168,8 @@ bool isGuaranteedParameter(ParameterConvention conv) { case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Pack_Guaranteed: return true; - + case ParameterConvention::Indirect_In_CXX: + return InCallee; case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: case ParameterConvention::Indirect_In: @@ -4185,6 +4194,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; @@ -4211,6 +4221,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: @@ -4291,6 +4302,10 @@ class SILParameterInfo { return getConvention() == ParameterConvention::Indirect_In; } + bool isIndirectInCXX() const { + return getConvention() == ParameterConvention::Indirect_In_CXX; + } + bool isIndirectInOut() const { return getConvention() == ParameterConvention::Indirect_Inout; } diff --git a/include/swift/SIL/ApplySite.h b/include/swift/SIL/ApplySite.h index 5ecf8dbdf2457..290b839302ecd 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 ec37ccbd9133b..fe0a266994679 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: @@ -110,6 +115,8 @@ struct SILArgumentConvention { case SILArgumentConvention::Direct_Owned: case SILArgumentConvention::Pack_Owned: return true; + case SILArgumentConvention::Indirect_In_CXX: + return !InCallee; case SILArgumentConvention::Indirect_In_Guaranteed: case SILArgumentConvention::Direct_Guaranteed: case SILArgumentConvention::Indirect_Inout: @@ -135,6 +142,8 @@ struct SILArgumentConvention { case SILArgumentConvention::Direct_Guaranteed: case SILArgumentConvention::Pack_Guaranteed: return true; + case SILArgumentConvention::Indirect_In_CXX: + return InCallee; case SILArgumentConvention::Indirect_Inout: case SILArgumentConvention::Indirect_In: case SILArgumentConvention::Indirect_Out: @@ -164,6 +173,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: @@ -190,6 +200,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 3da9cb078b112..1d3d934ffa134 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, @@ -153,6 +154,7 @@ inline swift::ParameterConvention getParameterConvention(BridgedArgumentConventi 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; @@ -171,6 +173,7 @@ inline BridgedArgumentConvention getArgumentConvention(swift::ParameterConventio case swift::ParameterConvention::Indirect_In_Guaranteed: return BridgedArgumentConvention::Indirect_In_Guaranteed; case swift::ParameterConvention::Indirect_Inout: return BridgedArgumentConvention::Indirect_Inout; case swift::ParameterConvention::Indirect_InoutAliasable: return BridgedArgumentConvention::Indirect_InoutAliasable; + case swift::ParameterConvention::Indirect_In_CXX: return BridgedArgumentConvention::Indirect_In_CXX; case swift::ParameterConvention::Direct_Owned: return BridgedArgumentConvention::Direct_Owned; case swift::ParameterConvention::Direct_Unowned: return BridgedArgumentConvention::Direct_Unowned; case swift::ParameterConvention::Direct_Guaranteed: return BridgedArgumentConvention::Direct_Guaranteed; diff --git a/include/swift/SIL/SILFunctionConventions.h b/include/swift/SIL/SILFunctionConventions.h index 05d4a750b1f09..f431f76e5a081 100644 --- a/include/swift/SIL/SILFunctionConventions.h +++ b/include/swift/SIL/SILFunctionConventions.h @@ -610,6 +610,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 9a0a2f73ff669..48a7ff8f2ceea 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1138,6 +1138,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 'X'; 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 4584b2b9e90c0..7386a96a94cde 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -6757,6 +6757,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: @@ -7526,6 +7527,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/ASTGen/Sources/ASTGen/TypeAttrs.swift b/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift index 24b08946c3420..9414956f4d7c7 100644 --- a/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift @@ -107,6 +107,7 @@ extension ASTGenVisitor { .in, .inConstant, .inGuaranteed, + .inCXX, .inout, .inoutAliasable, .moveOnly, diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 368d39e66880e..95435b491af9e 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -2161,6 +2161,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 'X': 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 a9cc1f0354b9f..5b0335b38b883 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -2107,6 +2107,7 @@ ManglingError Remangler::mangleImplFunctionType(Node *node, unsigned depth) { .Case("@inout", 'l') .Case("@inout_aliasable", 'b') .Case("@in_guaranteed", 'n') + .Case("@in_cxx", 'X') .Case("@in_constant", 'c') .Case("@owned", 'x') .Case("@guaranteed", 'g') diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 131e8f4101b8a..517ccb34a72d9 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -1755,6 +1755,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 ca630992f90f8..55830db7cdc23 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -527,6 +527,7 @@ void DistributedAccessor::decodeArgument(unsigned argumentIdx, } switch (param.getConvention()) { + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: { // The only way to load opaque type is to allocate a temporary // variable on the stack for it and initialize from the given address diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp index f91a493986f32..71d2b4994cd97 100644 --- a/lib/IRGen/GenFunc.cpp +++ b/lib/IRGen/GenFunc.cpp @@ -847,6 +847,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 @@ -1520,6 +1521,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: @@ -1631,6 +1633,7 @@ static llvm::Value *emitPartialApplicationForwarder( // - we received as unowned and are passing as guaranteed auto argConvention = conventions[0]; switch (argConvention) { + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: case ParameterConvention::Direct_Owned: if (!consumesContext) subIGF.emitNativeStrongRetain(rawData, subIGF.getDefaultAtomicity()); @@ -1725,6 +1728,7 @@ static llvm::Value *emitPartialApplicationForwarder( Explosion param; switch (fieldConvention) { + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: { auto initStackCopy = [&addressesToDeallocate, &needsAllocas, ¶m, @@ -2313,6 +2317,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 e0cec6b3dbac3..58b9ad03f3135 100644 --- a/lib/IRGen/GenObjC.cpp +++ b/lib/IRGen/GenObjC.cpp @@ -949,6 +949,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 a2080ed634238..458778cccba82 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -394,6 +394,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 a0d6a65571b4a..9f04be3781c02 100644 --- a/lib/SIL/IR/OperandOwnership.cpp +++ b/lib/SIL/IR/OperandOwnership.cpp @@ -482,6 +482,7 @@ static OperandOwnership getFunctionArgOwnership(SILArgumentConvention argConv, bool hasScopeInCaller) { switch (argConv) { + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Indirect_In: case SILArgumentConvention::Direct_Owned: case SILArgumentConvention::Pack_Owned: diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 605c6f44e1c5b..df7297d05742a 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -715,6 +715,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; } @@ -1052,6 +1053,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; } @@ -3209,6 +3211,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; } diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 48c81cfd289f4..e545ec6475cb1 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -1591,6 +1591,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 6d1271627a1e9..7c97bbe058615 100644 --- a/lib/SIL/IR/SILValue.cpp +++ b/lib/SIL/IR/SILValue.cpp @@ -307,6 +307,7 @@ ValueOwnershipKind::ValueOwnershipKind(const SILFunction &F, SILType Type, } switch (Convention) { + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Indirect_In_Guaranteed: value = moduleConventions.isTypeIndirectForIndirectParamConvention( Type.getASTType()) diff --git a/lib/SIL/Utils/MemAccessUtils.cpp b/lib/SIL/Utils/MemAccessUtils.cpp index 8bd5318ea798c..ef9ec6fd332e7 100644 --- a/lib/SIL/Utils/MemAccessUtils.cpp +++ b/lib/SIL/Utils/MemAccessUtils.cpp @@ -2195,6 +2195,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 8115403efedc2..5f28d1a3da88e 100644 --- a/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp +++ b/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp @@ -566,6 +566,7 @@ void MemoryLifetimeVerifier::setFuncOperandBits(BlockState &state, Operand &op, SILArgumentConvention convention, bool isTryApply) { switch (convention) { + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Indirect_In: killBits(state, op.get()); break; @@ -893,6 +894,7 @@ void MemoryLifetimeVerifier::checkFuncArgument(Bits &bits, Operand &argumentOp, requireNoStoreBorrowLocation(argumentOp.get(), applyInst); switch (argumentConvention) { + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Indirect_In: requireBitsSetForArgument(bits, &argumentOp); locations.clearBits(bits, argumentOp.get()); diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index e3392af31b7e2..a453323be69c7 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -544,6 +544,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: @@ -6484,6 +6485,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 2a50b1c81517f..1908bf080e934 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -5616,6 +5616,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: @@ -6871,6 +6872,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 dc8db819fab95..e4a6084b00e62 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -329,6 +329,10 @@ static ManagedValue emitManagedParameter(SILGenFunction &SGF, SILLocation loc, return ManagedValue::forBorrowedAddressRValue(value); } + case ParameterConvention::Indirect_In_CXX: + // Don't emit a cleanup if the parameter is @in_cxx. + return ManagedValue::forOwnedRValue(value, CleanupHandle::invalid()); + case ParameterConvention::Indirect_In: if (valueTL.isLoadable()) { return SGF.emitLoad(loc, value, valueTL, SGFContext(), IsTake); @@ -443,6 +447,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: @@ -1312,7 +1317,7 @@ static SILValue emitObjCUnconsumedArgument(SILGenFunction &SGF, SILValue arg) { auto &lowering = SGF.getTypeLowering(arg->getType()); // If address-only, make a +1 copy and operate on that. - if (lowering.isAddressOnly()) { + if (lowering.isAddressOnly() && SGF.useLoweredAddresses()) { auto tmp = SGF.emitTemporaryAllocation(loc, arg->getType().getObjectType()); SGF.B.createCopyAddr(loc, arg, tmp, IsNotTake, IsInitialization); return tmp; @@ -2190,6 +2195,7 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { case ParameterConvention::Indirect_InoutAliasable: param = ManagedValue::forLValue(paramValue); break; + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: param = emitManagedRValueWithCleanup(paramValue); break; diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp index 4e7b1ed0da2ea..b81ccf21bc51b 100644 --- a/lib/SILGen/SILGenBuilder.cpp +++ b/lib/SILGen/SILGenBuilder.cpp @@ -564,6 +564,7 @@ static ManagedValue createInputFunctionArgument( case SILArgumentConvention::Pack_Owned: return SGF.emitManagedPackWithCleanup(arg); + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Indirect_In: if (SGF.silConv.useLoweredAddresses()) return SGF.emitManagedBufferWithCleanup(arg); diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index c5f5f345f130f..8590f21ae9681 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -2067,6 +2067,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, @@ -2261,6 +2262,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"); @@ -2700,6 +2702,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: @@ -2846,6 +2849,7 @@ static ManagedValue manageYield(SILGenFunction &SGF, SILValue value, case ParameterConvention::Pack_Inout: return ManagedValue::forLValue(value); case ParameterConvention::Direct_Owned: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: case ParameterConvention::Pack_Owned: return SGF.emitManagedRValueWithCleanup(value); diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index 05ba3c9b0b96f..53a1fe05ce0c5 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -916,6 +916,7 @@ class ArgumentInitHelper { MarkUnresolvedNonCopyableValueInst::CheckKind:: ConsumableAndAssignable); break; + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Indirect_In_Guaranteed: argrv = SGF.B.createMarkUnresolvedNonCopyableValueInst( loc, argrv, @@ -1246,6 +1247,7 @@ static void emitCaptureArguments(SILGenFunction &SGF, case SILArgumentConvention::Indirect_InoutAliasable: case SILArgumentConvention::Indirect_In: case SILArgumentConvention::Indirect_In_Guaranteed: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Pack_Inout: case SILArgumentConvention::Pack_Owned: case SILArgumentConvention::Pack_Guaranteed: diff --git a/lib/SILOptimizer/Differentiation/VJPCloner.cpp b/lib/SILOptimizer/Differentiation/VJPCloner.cpp index 381b536a30c5a..ec162fdc9ba60 100644 --- a/lib/SILOptimizer/Differentiation/VJPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/VJPCloner.cpp @@ -1158,6 +1158,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 52c2d6eb63e5a..1574461e99049 100644 --- a/lib/SILOptimizer/Mandatory/AddressLowering.cpp +++ b/lib/SILOptimizer/Mandatory/AddressLowering.cpp @@ -3228,6 +3228,7 @@ void YieldRewriter::rewriteOperand(YieldInst *yieldInst, unsigned index) { case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: return; + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: ownership = OwnershipKind::Owned; break; diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp index a182be06a73b4..f58125876156c 100644 --- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp +++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp @@ -985,6 +985,7 @@ void ElementUseCollector::collectUses(SILValue Pointer, unsigned BaseEltNo) { llvm_unreachable("address value passed to indirect parameter"); // If this is an in-parameter, it is like a load. + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: addElementUses(BaseEltNo, PointeeType, User, DIUseKind::IndirectIn); diff --git a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp index 8f4b0061778af..36b79f42f12ca 100644 --- a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp +++ b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp @@ -113,6 +113,7 @@ static bool fixupReferenceCounts( bool hasOwnership = f->hasOwnership(); switch (convention) { + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: llvm_unreachable("Missing indirect copy"); diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp index 48ce0cd70a1b5..f3c36ea9b4fcd 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp @@ -430,6 +430,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: @@ -1024,6 +1025,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( @@ -2559,6 +2561,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/OwnershipModelEliminator.cpp b/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp index be5fff167124b..35849f4e47779 100644 --- a/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp +++ b/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp @@ -137,6 +137,7 @@ struct OwnershipModelEliminatorVisitor bool visitCopyValueInst(CopyValueInst *cvi); bool visitExplicitCopyValueInst(ExplicitCopyValueInst *cvi); bool visitExplicitCopyAddrInst(ExplicitCopyAddrInst *cai); + bool visitApplyInst(ApplyInst *ai); void splitDestroy(DestroyValueInst *destroy); bool visitDestroyValueInst(DestroyValueInst *dvi); @@ -360,6 +361,32 @@ bool OwnershipModelEliminatorVisitor::visitExplicitCopyAddrInst( return true; } +bool OwnershipModelEliminatorVisitor::visitApplyInst(ApplyInst *ai) { + auto callee = ai->getCallee(); + + if (!callee) + return false; + + // Insert destroy_addr for @in_cxx arguments. + auto fnTy = callee->getType().castTo(); + SILFunctionConventions fnConv(fnTy, ai->getModule()); + bool changed = false; + + for (int i = fnConv.getSILArgIndexOfFirstParam(), + e = i + fnConv.getNumParameters(); + i < e; ++i) { + auto paramInfo = fnConv.getParamInfoForSILArg(i); + if (!paramInfo.isIndirectInCXX()) + continue; + auto arg = ai->getArgument(i); + SILBuilderWithScope builder(ai->getNextInstruction(), builderCtx); + builder.createDestroyAddr(ai->getLoc(), arg); + changed = true; + } + + return changed; +} + bool OwnershipModelEliminatorVisitor::visitUnmanagedRetainValueInst( UnmanagedRetainValueInst *urvi) { // Now that we have set the unqualified ownership flag, destroy value diff --git a/lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp index 779f7f3fac6f6..e25458b0548c7 100644 --- a/lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp +++ b/lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp @@ -396,6 +396,7 @@ bool ElementUseCollector::collectUses(SILValue Pointer) { llvm_unreachable("address value passed to indirect parameter"); // If this is an in-parameter, it is like a load. + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: Uses.emplace_back(User, PMOUseKind::IndirectIn); diff --git a/lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp b/lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp index 499f5b3dfcdd4..24ccbb0842762 100644 --- a/lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp +++ b/lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp @@ -144,6 +144,7 @@ static void getAssignByWrapperArgsRecursively(SmallVectorImpl &args, forCleanup.createDestroyValue(loc, src); break; case SILArgumentConvention::Direct_Unowned: + case SILArgumentConvention::Indirect_In_CXX: case SILArgumentConvention::Indirect_In: case SILArgumentConvention::Direct_Owned: break; diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp index f4f57d8cfe890..033f5d8296308 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp @@ -690,6 +690,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 875c85c90d617..84191db8dc919 100644 --- a/lib/SILOptimizer/Transforms/PartialApplySimplification.cpp +++ b/lib/SILOptimizer/Transforms/PartialApplySimplification.cpp @@ -180,6 +180,7 @@ static bool isSimplePartialApply(SILModule &M, // +1 arguments need a thunk to stage a copy for the callee to consume. case ParameterConvention::Direct_Owned: + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: return false; } @@ -455,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)); @@ -608,6 +610,7 @@ rewriteKnownCalleeWithExplicitContext(SILFunction *callee, // Load a copy of the value from the box. projectedArg = B.createLoad(loc, proj, LoadOwnershipQualifier::Copy); break; + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: { // Allocate space for a copy of the value that can be consumed by the // function body. We'll need to deallocate the stack slot after the @@ -654,6 +657,7 @@ rewriteKnownCalleeWithExplicitContext(SILFunction *callee, projectedArg = B.createLoad(loc, proj, LoadOwnershipQualifier::Unqualified); B.createRetainValue(loc, projectedArg, Atomicity::Atomic); break; + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: { // Allocate space for a copy of the value that can be consumed by the // function body. We'll need to deallocate the stack slot after the @@ -791,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 d72a60bc4a900..fdbc17f85719d 100644 --- a/lib/SILOptimizer/Utils/CastOptimizer.cpp +++ b/lib/SILOptimizer/Utils/CastOptimizer.cpp @@ -693,6 +693,7 @@ CastOptimizer::optimizeBridgedSwiftToObjCCast(SILDynamicCastInst dynamicCast) { case ParameterConvention::Pack_Inout: case ParameterConvention::Direct_Owned: case ParameterConvention::Indirect_In: + case ParameterConvention::Indirect_In_CXX: // Currently this // cannot appear, because the _bridgeToObjectiveC protocol witness method // always receives the this pointer (= the source) as guaranteed. diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index 36501c0d59ffe..d7f0662aca0b8 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -771,6 +771,7 @@ void ReabstractionInfo::createSubstitutedAndSpecializedTypes() { continue; switch (PI.getConvention()) { + case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: { Conversions.set(IdxToInsert); diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp index e69eee19d59f3..9d598d5bedb08 100644 --- a/lib/SILOptimizer/Utils/SILInliner.cpp +++ b/lib/SILOptimizer/Utils/SILInliner.cpp @@ -461,6 +461,7 @@ void SILInlineCloner::cloneInline(ArrayRef AppliedArgs) { auto calleeConv = getCalleeFunction()->getConventions(); SmallBitVector borrowedArgs(AppliedArgs.size()); SmallBitVector copiedArgs(AppliedArgs.size()); + SmallBitVector inCxxArgs(AppliedArgs.size()); if (!Apply->getFunction()->hasOwnership()) { for (auto p : llvm::enumerate(AppliedArgs)) { @@ -511,6 +512,9 @@ void SILInlineCloner::cloneInline(ArrayRef AppliedArgs) { } } } + + if (paramInfo.getConvention() == ParameterConvention::Indirect_In_CXX) + inCxxArgs[idx] = true; } } } @@ -570,6 +574,20 @@ void SILInlineCloner::cloneInline(ArrayRef AppliedArgs) { } } + if (inCxxArgs.any()) { + for (unsigned i : indices(AppliedArgs)) { + if (!inCxxArgs.test(i)) { + continue; + } + + for (auto *insertPt : endBorrowInsertPts) { + SILBuilderWithScope returnBuilder(insertPt->getParent()->begin(), + getBuilder()); + returnBuilder.emitDestroyOperation(Apply.getLoc(), entryArgs[i]); + } + } + } + // Visit original BBs in depth-first preorder, starting with the // entry block, cloning all instructions and terminators. cloneFunctionBody(getCalleeFunction(), callerBlock, entryArgs); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 24f410b727a2d..1e46bb4ba841b 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4475,6 +4475,7 @@ SILParameterInfo TypeResolver::resolveSILParameter( convention = ParameterConvention::KIND; \ return true; OWNERSHIP(InGuaranteed, Indirect_In_Guaranteed) + OWNERSHIP(InCXX, Indirect_In_CXX) OWNERSHIP(In, Indirect_In) OWNERSHIP(InConstant, Indirect_In) OWNERSHIP(Inout, Indirect_Inout) diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 4ae534c3e36e6..a3b74ba894ca8 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -6617,6 +6617,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 2ae35a9daae0c..7632bad965eb6 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -389,6 +389,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 3a21af3274075..8413d64d2a89a 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -5186,6 +5186,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/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index 0eae2180776ba..206389b72cd6a 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -475,3 +475,4 @@ $sSRyxG15Synchronization19AtomicRepresentableABRi1_zrlMc ---> protocol conforman $s23variadic_generic_opaque2G2VyAA2S1V_AA2S2VQPGAA1PHPAeA1QHPyHC_AgaJHPyHCHX_HC ---> concrete protocol conformance variadic_generic_opaque.G2 to protocol conformance ref (type's module) variadic_generic_opaque.P with conditional requirements: (pack protocol conformance (concrete protocol conformance variadic_generic_opaque.S1 to protocol conformance ref (type's module) variadic_generic_opaque.Q, concrete protocol conformance variadic_generic_opaque.S2 to protocol conformance ref (type's module) variadic_generic_opaque.Q)) $s9MacroUser0023macro_expandswift_elFCffMX436_4_23bitwidthNumberedStructsfMf_ ---> freestanding macro expansion #1 of bitwidthNumberedStructs in module MacroUser file macro_expand.swift line 437 column 5 +$sxq_IyXd_D ---> @callee_unowned (@in_cxx A) -> (@unowned B) diff --git a/test/Interop/Cxx/class/Inputs/closure.h b/test/Interop/Cxx/class/Inputs/closure.h index aab288483fbf1..7081ff54c7b08 100644 --- a/test/Interop/Cxx/class/Inputs/closure.h +++ b/test/Interop/Cxx/class/Inputs/closure.h @@ -2,33 +2,47 @@ #define __CLOSURE__ struct NonTrivial { - NonTrivial() { p = new int(123); } + NonTrivial() noexcept { p = new int(123); } ~NonTrivial() { delete p; } - NonTrivial(const NonTrivial &other); + NonTrivial(const NonTrivial &other) noexcept { + p = new int(*other.p); + } int *p; }; -void cfunc2(void (*fp)(NonTrivial)) { - (*fp)(NonTrivial()); +void cfunc(void (^ _Nonnull block)(NonTrivial)) noexcept { + block(NonTrivial()); } +void cfunc2(void (*_Nonnull fp)(NonTrivial)) noexcept { (*fp)(NonTrivial()); } + +NonTrivial cfunc3(NonTrivial, int, NonTrivial); + #if __OBJC__ struct ARCStrong { id a; }; -void cfuncARCStrong(void (*_Nonnull)(ARCStrong)); +void cfuncARCStrong(void (*_Nonnull)(ARCStrong)) noexcept ; #endif +void cfuncReturnNonTrivial(NonTrivial (^_Nonnull)()) noexcept; +void cfuncReturnNonTrivial2(NonTrivial (*_Nonnull)()) noexcept; + struct ARCWeak { #if __OBJC__ __weak _Nullable id m; #endif }; -void cfuncReturnNonTrivial(NonTrivial (^_Nonnull)()) noexcept; -void cfuncReturnNonTrivial2(NonTrivial (*_Nonnull)()) noexcept; +void cfuncARCWeak(void (^ _Nonnull block)(ARCWeak)) noexcept { + block(ARCWeak()); +} + +void cfunc(NonTrivial) noexcept; +void cfuncARCWeak(ARCWeak) noexcept; -void (*_Nonnull getFnPtr2() noexcept)(ARCWeak) noexcept; +void (* _Nonnull getFnPtr() noexcept)(NonTrivial) noexcept; +void (* _Nonnull getFnPtr2() noexcept)(ARCWeak) noexcept; #endif // __CLOSURE__ 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-irgen.swift b/test/Interop/Cxx/class/closure-thunk-irgen.swift index 520c1131d845d..78e43d8642bc0 100644 --- a/test/Interop/Cxx/class/closure-thunk-irgen.swift +++ b/test/Interop/Cxx/class/closure-thunk-irgen.swift @@ -4,6 +4,35 @@ import Closure +// CHECK: define linkonce_odr hidden void @"$sSo10NonTrivialVIegn_ABIeyBX_TR"(ptr %[[V0:.*]], ptr %[[V1:.*]]) +// CHECK: %[[V2:.*]] = getelementptr inbounds { %{{.*}}, %{{.*}} }, ptr %[[V0]], i32 0, i32 1 +// CHECK-NEXT: %[[_FN:.*]] = getelementptr inbounds %{{.*}}, ptr %[[V2]], i32 0, i32 0 +// CHECK-NEXT: %[[V3:.*]] = load ptr, ptr %[[_FN]], align 8 +// CHECK-NEXT: %[[_DATA:.*]] = getelementptr inbounds %{{.*}}, ptr %[[V2]], i32 0, i32 1 +// CHECK-NEXT: %[[V4:.*]] = load ptr, ptr %[[_DATA]], align 8 +// CHECK-NEXT: call ptr @swift_retain(ptr returned %[[V4]]) +// CHECK-NEXT: call swiftcc void %[[V3]](ptr noalias dereferenceable(8) %[[V1]], ptr swiftself %[[V4]]) +// CHECK-NEXT: call void @swift_release(ptr %[[V4]]) +// CHECK-NEXT: ret void + +// NonTrivial is destroyed by the caller. +public func testClosureToBlock() { + cfunc({NonTrivial in}) +} + +// CHECK: define internal void @"$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_To"(ptr %[[V0:.*]]) +// CHECK: %[[V1:.*]] = alloca %{{.*}}, align 8 +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr %[[V1]]) +// CHECK-NEXT: call {{void|ptr}} @_ZN10NonTrivialC1ERKS_(ptr %[[V1]], ptr %[[V0]]) +// CHECK-NEXT: call swiftcc void @"$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_"(ptr noalias dereferenceable(8) %[[V1]]) +// CHECK-NEXT: call {{void|ptr}} @_ZN10NonTrivialD1Ev(ptr %[[V1]]) +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr %[[V1]]) +// CHECK-NEXT: ret void + +public func testClosureToFuncPtr() { + cfunc2({N in}) +} + // CHECK: define internal void @"$s4main36testClosureToFuncPtrReturnNonTrivialyyFSo0hI0VycfU_To"(ptr noalias sret(%{{.*}}) %[[V0:.*]]) // CHECK: call swiftcc void @"$s4main36testClosureToFuncPtrReturnNonTrivialyyFSo0hI0VycfU_"(ptr noalias sret(%{{.*}}) %[[V0]]) // CHECK: ret void @@ -11,3 +40,33 @@ import Closure public func testClosureToFuncPtrReturnNonTrivial() { cfuncReturnNonTrivial2({() -> NonTrivial in return NonTrivial()}); } + +// CHECK: define swiftcc { ptr, ptr } @"$s4main13returnFuncPtrySo10NonTrivialVcyF"() +// CHECK: %[[V0:.*]] = call ptr @_Z8getFnPtrv() +// CHECK: %[[V1:.*]] = call noalias ptr @swift_allocObject(ptr getelementptr inbounds (%{{.*}}, ptr @{{.*}}, i32 0, i32 2), i64 24, i64 7) #4 +// CHECK: %[[V2:.*]] = getelementptr inbounds <{ %{{.*}}, ptr }>, ptr %[[V1]], i32 0, i32 1 +// CHECK: store ptr %[[V0]], ptr %[[V2]], align 8 +// CHECK: %[[V3:.*]] = insertvalue { ptr, ptr } { ptr @"$sSo10NonTrivialVIetCX_ABIegn_TRTA", ptr undef }, ptr %[[V1]], 1 +// CHECK: ret { ptr, ptr } %[[V3]] + +// CHECK: define linkonce_odr hidden swiftcc void @"$sSo10NonTrivialVIetCX_ABIegn_TR"(ptr noalias dereferenceable(8) %[[V0:.*]], ptr %[[V1:.*]]) +// CHECK: %[[V2:.*]] = alloca %{{.*}}, align 8 +// CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr %[[V2]]) +// CHECK: call {{(void|ptr)}} @_ZN10NonTrivialC1ERKS_(ptr %[[V2]], ptr %[[V0]]) +// CHECK: invoke void %[[V1]](ptr %[[V2]]) +// CHECK: to label %[[INVOKE_CONT:.*]] unwind label %{{.*}} + +// CHECK: [[INVOKE_CONT]]: +// CHECK-NEXT: call {{(void|ptr)}} @_ZN10NonTrivialD1Ev(ptr %[[V2]]) +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr %[[V2]]) +// CHECK-NEXT: ret void + +// CHECK: define internal swiftcc void @"$sSo10NonTrivialVIetCX_ABIegn_TRTA"(ptr noalias dereferenceable(8) %[[V0]], ptr swiftself %[[V1]]) +// CHECK: %[[V2]] = getelementptr inbounds <{ %{{.*}}, ptr }>, ptr %[[V1]], i32 0, i32 1 +// CHECK-NEXT: %[[V3]] = load ptr, ptr %[[V2]], align 8 +// CHECK-NEXT: tail call swiftcc void @"$sSo10NonTrivialVIetCX_ABIegn_TR"(ptr noalias dereferenceable(8) %[[V0]], ptr %[[V3]]) +// CHECK-NEXT: ret void + +public func returnFuncPtr() -> (NonTrivial) -> () { + return getFnPtr() +} diff --git a/test/Interop/Cxx/class/closure-thunk-macosx-sil.swift b/test/Interop/Cxx/class/closure-thunk-macosx-sil.swift new file mode 100644 index 0000000000000..bc5f96b97e42d --- /dev/null +++ b/test/Interop/Cxx/class/closure-thunk-macosx-sil.swift @@ -0,0 +1,37 @@ +// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-sil %s | %FileCheck %s + +// REQUIRES: OS=macosx + +import Closure + +// CHECK: sil @$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 %[[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: strong_release %[[V8]] : $@convention(block) (@in ARCWeak) -> () +// CHECK: %[[V12:.*]] = tuple () +// CHECK: return %[[V12]] : $() + +// CHECK: sil shared [transparent] [reabstraction_thunk] @$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 %[[V2]] : $*@callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: strong_retain %[[V3]] : $@callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: apply %[[V3]](%[[V1]]) : $@callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: %[[V6:.*]] = tuple () +// CHECK: destroy_addr %[[V1]] : $*ARCWeak +// CHECK: strong_release %[[V3]] : $@callee_guaranteed (@in_guaranteed ARCWeak) -> () +// CHECK: return %[[V6]] : $() + +// ARCWeak is destroyed by the callee. +public func testClosureToBlockARCWeak() { + cfuncARCWeak({ARCWeak in}) +} diff --git a/test/Interop/Cxx/class/closure-thunk.swift b/test/Interop/Cxx/class/closure-thunk.swift index 6a91813d2f325..2034cdff1fe26 100644 --- a/test/Interop/Cxx/class/closure-thunk.swift +++ b/test/Interop/Cxx/class/closure-thunk.swift @@ -1,26 +1,83 @@ -// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-silgen %s | %FileCheck %s +// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-sil %s | %FileCheck --dump-input-filter=all %s + +// REQUIRES: OS=macosx || OS=linux-android 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 @$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 %[[V3]] : $*@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V7:.*]] = function_ref @$sSo10NonTrivialVIegn_ABIeyBX_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: strong_release %[[V8]] : $@convention(block) (@in_cxx NonTrivial) -> () +// CHECK: %[[V12:.*]] = tuple () +// CHECK: return %[[V12]] : $() + +// CHECK: sil shared [transparent] [reabstraction_thunk] @$sSo10NonTrivialVIegn_ABIeyBX_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 %[[V2]] : $*@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: strong_retain %[[V3]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: apply %[[V3]](%[[V1]]) : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V6:.*]] = tuple () +// CHECK: strong_release %[[V3]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: return %[[V6]] : $() + +// NonTrivial is destroyed by the caller. +public func testClosureToBlock() { + cfunc({NonTrivial in}) +} -// CHECK: sil private [ossa] @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_ : $@convention(thin) (@in_guaranteed NonTrivial) -> () { +// CHECK: sil @$s4main20testClosureToFuncPtryyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = function_ref @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_To : $@convention(c) (@in_cxx NonTrivial) -> () +// CHECK: %[[V1:.*]] = function_ref @_Z6cfunc2PFv10NonTrivialE : $@convention(c) (@convention(c) (@in_cxx NonTrivial) -> ()) -> () +// CHECK: apply %[[V1]](%[[V0]]) : $@convention(c) (@convention(c) (@in_cxx NonTrivial) -> ()) -> () +// CHECK: %[[V3:.*]] = tuple () +// CHECK: return %[[V3]] : $() -// CHECK: sil private [thunk] [ossa] @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_To : $@convention(c) (@in NonTrivial) -> () { +// CHECK: sil private [thunk] @$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_To : $@convention(c) (@in_cxx 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 +// 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}) + cfunc2({N in}) +} + +// CHECK: sil @$s4main13returnFuncPtrySo10NonTrivialVcyF : $@convention(thin) () -> @owned @callee_guaranteed (@in_guaranteed NonTrivial) -> () { +// CHECK: %[[V0:.*]] = function_ref @_Z8getFnPtrv : $@convention(c) () -> @convention(c) (@in_cxx NonTrivial) -> () +// CHECK: %[[V1:.*]] = apply %[[V0]]() : $@convention(c) () -> @convention(c) (@in_cxx NonTrivial) -> () +// CHECK: %[[V2:.*]] = function_ref @$sSo10NonTrivialVIetCX_ABIegn_TR : $@convention(thin) (@in_guaranteed NonTrivial, @convention(c) (@in_cxx NonTrivial) -> ()) -> () +// CHECK: %[[V3:.*]] = partial_apply [callee_guaranteed] %[[V2]](%[[V1]]) : $@convention(thin) (@in_guaranteed NonTrivial, @convention(c) (@in_cxx NonTrivial) -> ()) -> () +// CHECK: return %[[V3]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () + +// CHECK: sil shared [transparent] [reabstraction_thunk] @$sSo10NonTrivialVIetCX_ABIegn_TR : $@convention(thin) (@in_guaranteed NonTrivial, @convention(c) (@in_cxx NonTrivial) -> ()) -> () { +// CHECK: bb0(%[[V0:.*]] : $*NonTrivial, %[[V1:.*]] : $@convention(c) (@in_cxx NonTrivial) -> ()): +// CHECK: %[[V2:.*]] = alloc_stack $NonTrivial +// CHECK: copy_addr %[[V0]] to [init] %[[V2]] : $*NonTrivial +// CHECK: apply %[[V1]](%[[V2]]) : $@convention(c) (@in_cxx NonTrivial) -> () +// CHECK: destroy_addr %[[V2]] : $*NonTrivial +// CHECK: %[[V6:.*]] = tuple () +// CHECK: dealloc_stack %[[V2]] : $*NonTrivial +// CHECK: return %[[V6]] : $() + +public func returnFuncPtr() -> (NonTrivial) -> () { + return getFnPtr() } -// CHECK: sil private [thunk] [ossa] @$s4main36testClosureToFuncPtrReturnNonTrivialyyFSo0hI0VycfU_To : $@convention(c) () -> @out NonTrivial { +// CHECK: sil private [thunk] @$s4main36testClosureToFuncPtrReturnNonTrivialyyFSo0hI0VycfU_To : $@convention(c) () -> @out NonTrivial { // CHECK: bb0(%[[V0:.*]] : $*NonTrivial): // CHECK: %[[V1:.*]] = function_ref @$s4main36testClosureToFuncPtrReturnNonTrivialyyFSo0hI0VycfU_ : $@convention(thin) () -> @out NonTrivial // CHECK: %[[V2:.*]] = apply %[[V1]](%[[V0]]) : $@convention(thin) () -> @out NonTrivial diff --git a/test/Interop/Cxx/class/function-call-irgen.swift b/test/Interop/Cxx/class/function-call-irgen.swift new file mode 100644 index 0000000000000..c2d45e7ddf39a --- /dev/null +++ b/test/Interop/Cxx/class/function-call-irgen.swift @@ -0,0 +1,39 @@ +// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-irgen %s | %FileCheck --dump-input-filter=all %s + +// REQUIRES: OS=macosx || OS=linux-android + +import Closure + +// CHECK: define swiftcc void @"$s4main14testNonTrivialyyF"() +// CHECK: %[[V0:.*]] = alloca %{{.*}}, align 8 +// CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr %[[V0]]) +// CHECK: call {{(void|ptr)}} @__swift_cxx_ctor_ZN10NonTrivialC1Ev(ptr %[[V0]]) +// CHECK: call void @_Z5cfunc10NonTrivial(ptr %[[V0]]) +// CHECK: call {{(void|ptr)}} @_ZN10NonTrivialD1Ev(ptr %[[V0]]) +// CHECK: call void @llvm.lifetime.end.p0(i64 8, ptr %[[V0]]) +// CHECK: ret void + +public func testNonTrivial() { + cfunc(NonTrivial()); +} + +// CHECK: define swiftcc void @"$s4main29testNonTrivialFunctionPointeryyF"() +// CHECK: %[[F_DEBUG:.*]] = alloca ptr, align 8 +// CHECK: call void @llvm.memset.p0.i64(ptr align 8 %[[F_DEBUG]], i8 0, i64 8, i1 false) +// CHECK: %[[V0:.*]] = alloca %{{.*}}, align 8 +// CHECK: %[[V1:.*]] = call ptr @_Z8getFnPtrv() +// CHECK: store ptr %[[V1]], ptr %[[F_DEBUG]], align 8 +// CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr %[[V0]]) +// CHECK: call {{(void|ptr)}} @__swift_cxx_ctor_ZN10NonTrivialC1Ev(ptr %[[V0]]) +// CHECK: invoke void %[[V1]](ptr %[[V0]]) +// CHECK: to label %[[INVOKE_CONT:.*]] unwind label %{{.*}} + +// CHECK: [[INVOKE_CONT]]: +// CHECK: call {{(void|ptr)}} @_ZN10NonTrivialD1Ev(ptr %[[V0]]) +// CHECK: call void @llvm.lifetime.end.p0(i64 8, ptr %[[V0]]) +// CHECK: ret void + +public func testNonTrivialFunctionPointer() { + let f = getFnPtr() + f(NonTrivial()) +} 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.swift b/test/Interop/Cxx/class/function-call.swift new file mode 100644 index 0000000000000..140bc5178b758 --- /dev/null +++ b/test/Interop/Cxx/class/function-call.swift @@ -0,0 +1,59 @@ +// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-sil %s | %FileCheck --dump-input-filter=all %s + +// REQUIRES: OS=macosx || OS=linux-android + +import Closure + +// CHECK: sil @$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 @$s4main15testDestroyAddryyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = alloc_stack [lexical] [var_decl] $NonTrivial, var, name "a" +// CHECK-NEXT: %[[V1:.*]] = alloc_stack $NonTrivial +// CHECK: %[[V2:.*]] = function_ref @_ZN10NonTrivialC1Ev : $@convention(c) () -> @out NonTrivial +// CHECK-NEXT: apply %[[V2]](%[[V1]]) : $@convention(c) () -> @out NonTrivial +// CHECK-NEXT: %[[V4:.*]] = integer_literal $Builtin.Int32, 1 +// CHECK-NEXT: %[[V5:.*]] = struct $Int32 (%[[V4]] : $Builtin.Int32) +// CHECK-NEXT: %[[V6:.*]] = alloc_stack $NonTrivial +// CHECK: %[[V7:.*]] = function_ref @_ZN10NonTrivialC1Ev : $@convention(c) () -> @out NonTrivial +// CHECK-NEXT: apply %[[V7]](%[[V6]]) : $@convention(c) () -> @out NonTrivial +// CHECK: %[[V16:.*]] = function_ref @_Z6cfunc310NonTrivialiS_ : $@convention(c) (@in_cxx NonTrivial, Int32, @in_cxx NonTrivial) -> @out NonTrivial +// CHECK-NEXT: apply %[[V16]](%[[V0]], %[[V1]], %[[V5]], %[[V6]]) : $@convention(c) (@in_cxx NonTrivial, Int32, @in_cxx NonTrivial) -> @out NonTrivial +// CHECK-NEXT: destroy_addr %[[V6]] : $*NonTrivial +// CHECK-NEXT: destroy_addr %[[V1]] : $*NonTrivial +// CHECK-NEXT: dealloc_stack %[[V6]] : $*NonTrivial +// CHECK-NEXT: dealloc_stack %[[V1]] : $*NonTrivial +// CHECK-NEXT: destroy_addr %[[V0]] : $*NonTrivial +// CHECK-NEXT: dealloc_stack %[[V0]] : $*NonTrivial +// CHECK-NEXT: %[[V17:.*]] = tuple () +// CHECK-NEXT: return %[[V17]] : $() + +// Check that destroy_addr instructions are emitted in the expected order. +public func testDestroyAddr() { + var a = cfunc3(NonTrivial(), 1, NonTrivial()) +} + +// CHECK: sil @$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/inline-in-cxx.sil b/test/Interop/Cxx/class/inline-in-cxx.sil new file mode 100644 index 0000000000000..85f3091be2620 --- /dev/null +++ b/test/Interop/Cxx/class/inline-in-cxx.sil @@ -0,0 +1,38 @@ +// RUN: %target-sil-opt -enable-sil-verify-all --enable-experimental-cxx-interop -inline --I %S/Inputs %s | %FileCheck %s + +import Swift +import Closure + +sil [transparent] [ossa] @f0 : $@convention(c) (@in_cxx NonTrivial, Int, @in_cxx NonTrivial) -> () { +bb0(%0 : $*NonTrivial, %1 : $Int, %2 : $*NonTrivial): + %3 = tuple () + return %3 : $() +} + +// CHECK: sil [ossa] @caller0 : $@convention(thin) (@in_guaranteed NonTrivial, Int) -> () { +// CHECK: bb0(%[[V0:.*]] : $*NonTrivial, %[[V1:.*]] : $Int): +// CHECK: %[[V2:.*]] = alloc_stack [lexical] $NonTrivial +// CHECK: %[[V3:.*]] = alloc_stack [lexical] $NonTrivial +// CHECK: copy_addr %[[V0]] to [init] %[[V2]] : $*NonTrivial +// CHECK: copy_addr %[[V0]] to [init] %[[V3]] : $*NonTrivial +// CHECK: tuple () +// CHECK: destroy_addr %[[V3]] : $*NonTrivial +// CHECK: destroy_addr %[[V2]] : $*NonTrivial +// CHECK: dealloc_stack %[[V3]] : $*NonTrivial +// CHECK: dealloc_stack %[[V2]] : $*NonTrivial +// CHECK: %[[V9:.*]] = tuple () +// CHECK: return %[[V9]] : $() + +sil [ossa] @caller0 : $@convention(thin) (@in_guaranteed NonTrivial, Int) -> () { +bb0(%0 : $*NonTrivial, %1 : $Int): + %2 = alloc_stack $NonTrivial + %3 = alloc_stack $NonTrivial + copy_addr %0 to [init] %2: $*NonTrivial + copy_addr %0 to [init] %3: $*NonTrivial + %4 = function_ref @f0 : $@convention(c) (@in_cxx NonTrivial, Int, @in_cxx NonTrivial) -> () + %5 = apply %4(%2, %1, %3) : $@convention(c) (@in_cxx NonTrivial, Int, @in_cxx NonTrivial) -> () + dealloc_stack %3 : $*NonTrivial + dealloc_stack %2 : $*NonTrivial + %8 = tuple () + return %8 : $() +} 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"()