diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 0b0afee837948..87fcaf8160e4f 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -15,6 +15,7 @@ #include "ExecutorBreadcrumb.h" #include "Initialization.h" #include "LValue.h" +#include "ManagedValue.h" #include "RValue.h" #include "SILGenFunction.h" #include "SILGenFunctionBuilder.h" @@ -29,7 +30,9 @@ #include "swift/Basic/Generators.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILLocation.h" #include "swift/SIL/SILUndef.h" +#include "swift/SIL/SILValue.h" #include "swift/SIL/TypeLowering.h" #include @@ -82,13 +85,14 @@ class LoweredParamsInContextGenerator { } // end anonymous namespace -static ManagedValue emitManagedParameter(SILGenFunction &SGF, - SILValue value, bool isOwned) { +static ManagedValue emitManagedParameter(SILGenFunction &SGF, SILValue value, + bool isOwned, SILLocation loc) { if (isOwned) { return SGF.emitManagedRValueWithCleanup(value); - } else { - return ManagedValue::forBorrowedRValue(value); } + if (value->getOwnershipKind() == OwnershipKind::Unowned) + return ManagedValue::forUnownedObjectValue(value).ensurePlusOne(SGF, loc); + return ManagedValue::forBorrowedRValue(value); } static SILValue emitConstructorMetatypeArg(SILGenFunction &SGF, @@ -216,7 +220,8 @@ static RValue emitImplicitValueConstructorArg(SILGenFunction &SGF, [&](Initialization *eltInit) { auto eltAddr = SGF.B.createPackElementGet(loc, packIndex, arg, eltTy); - ManagedValue eltMV = emitManagedParameter(SGF, eltAddr, argIsConsumed); + ManagedValue eltMV = + emitManagedParameter(SGF, eltAddr, argIsConsumed, loc); eltMV = SGF.B.createLoadIfLoadable(loc, eltMV); eltInit->copyOrInitValueInto(SGF, loc, eltMV, argIsConsumed); eltInit->finishInitialization(SGF); @@ -226,7 +231,7 @@ static RValue emitImplicitValueConstructorArg(SILGenFunction &SGF, return RValue::forInContext(); } - ManagedValue mvArg = emitManagedParameter(SGF, arg, argIsConsumed); + ManagedValue mvArg = emitManagedParameter(SGF, arg, argIsConsumed, loc); // This can happen if the value is resilient in the calling convention // but not resilient locally. diff --git a/test/Interop/Cxx/foreign-reference/Inputs/logging-frts.h b/test/Interop/Cxx/foreign-reference/Inputs/logging-frts.h new file mode 100644 index 0000000000000..0b7c8b5c3019e --- /dev/null +++ b/test/Interop/Cxx/foreign-reference/Inputs/logging-frts.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +class SharedFRT { +public: + SharedFRT() : _refCount(1) { logMsg("Ctor"); } + +private: + void logMsg(const char *s) const { + printf("RefCount: %d, message: %s\n", _refCount, s); + } + + ~SharedFRT() { logMsg("Dtor"); } + SharedFRT(const SharedFRT &) = delete; + SharedFRT &operator=(const SharedFRT &) = delete; + SharedFRT(SharedFRT &&) = delete; + SharedFRT &operator=(SharedFRT &&) = delete; + + int _refCount; + + friend void retainSharedFRT(SharedFRT *_Nonnull); + friend void releaseSharedFRT(SharedFRT *_Nonnull); +} SWIFT_SHARED_REFERENCE(retainSharedFRT, releaseSharedFRT); + +class MyToken { +public: + MyToken() = default; + MyToken(MyToken const &) {} +}; + +inline void retainSharedFRT(SharedFRT *_Nonnull x) { + ++x->_refCount; + x->logMsg("retain"); +} + +inline void releaseSharedFRT(SharedFRT *_Nonnull x) { + --x->_refCount; + x->logMsg("release"); + if (x->_refCount == 0) + delete x; +} diff --git a/test/Interop/Cxx/foreign-reference/Inputs/module.modulemap b/test/Interop/Cxx/foreign-reference/Inputs/module.modulemap index 8859a47557f77..23ce347297fa7 100644 --- a/test/Interop/Cxx/foreign-reference/Inputs/module.modulemap +++ b/test/Interop/Cxx/foreign-reference/Inputs/module.modulemap @@ -77,3 +77,8 @@ module VirtMethodWithRvalRef { header "virtual-methods-with-rvalue-reference.h" requires cplusplus } + +module LoggingFrts { + header "logging-frts.h" + requires cplusplus +} diff --git a/test/Interop/Cxx/foreign-reference/frts-as-fields.swift b/test/Interop/Cxx/foreign-reference/frts-as-fields.swift new file mode 100644 index 0000000000000..7fcd7a4564ecf --- /dev/null +++ b/test/Interop/Cxx/foreign-reference/frts-as-fields.swift @@ -0,0 +1,30 @@ +// RUN: %target-run-simple-swift(-I %swift_src_root/lib/ClangImporter/SwiftBridging -I %S/Inputs -cxx-interoperability-mode=default -Xfrontend -disable-availability-checking -Onone) | %FileCheck %s + +// REQUIRES: executable_test + +import LoggingFrts + +struct SwiftStruct { + var frt: SharedFRT + var token: MyToken +} + +func go() { + let frt = SharedFRT() + let token = MyToken() + let _ = SwiftStruct(frt: frt, token: token) + let _ = SwiftStruct(frt: frt, token: token) + let _ = SwiftStruct(frt: frt, token: token) +} + +go() + +// CHECK: RefCount: 1, message: Ctor +// CHECK-NEXT: RefCount: 2, message: retain +// CHECK-NEXT: RefCount: 1, message: release +// CHECK-NEXT: RefCount: 2, message: retain +// CHECK-NEXT: RefCount: 1, message: release +// CHECK-NEXT: RefCount: 2, message: retain +// CHECK-NEXT: RefCount: 1, message: release +// CHECK-NEXT: RefCount: 0, message: release +// CHECK-NEXT: RefCount: 0, message: Dtor \ No newline at end of file