diff --git a/lib/SILGen/Cleanup.cpp b/lib/SILGen/Cleanup.cpp index 20eb0cc3c8e7e..868a0f1c6ecab 100644 --- a/lib/SILGen/Cleanup.cpp +++ b/lib/SILGen/Cleanup.cpp @@ -359,14 +359,16 @@ void CleanupStateRestorationScope::pop() && { popImpl(); } //===----------------------------------------------------------------------===// CleanupCloner::CleanupCloner(SILGenFunction &SGF, const ManagedValue &mv) - : SGF(SGF), hasCleanup(mv.hasCleanup()), isLValue(mv.isLValue()), - writebackBuffer(None) { + : SGF(SGF), writebackBuffer(None), hasCleanup(mv.hasCleanup()), + isLValue(mv.isLValue()), isFormalAccess(false) { if (hasCleanup) { auto handle = mv.getCleanup(); auto state = SGF.Cleanups.getFlagsAndWritebackBuffer(handle); - if (SILValue value = std::get<1>(state).getValueOr(SILValue())) { + using RawTy = std::underlying_type::type; + if (RawTy(std::get<0>(state)) & RawTy(Cleanup::Flags::FormalAccessCleanup)) + isFormalAccess = true; + if (SILValue value = std::get<1>(state).getValueOr(SILValue())) writebackBuffer = value; - } } } @@ -405,8 +407,16 @@ ManagedValue CleanupCloner::clone(SILValue value) const { } if (value->getType().isAddress()) { + if (isFormalAccess) { + auto loc = RegularLocation::getAutoGeneratedLocation(); + return SGF.emitFormalAccessManagedBufferWithCleanup(loc, value); + } return SGF.emitManagedBufferWithCleanup(value); } + if (isFormalAccess) { + auto loc = RegularLocation::getAutoGeneratedLocation(); + return SGF.emitFormalAccessManagedRValueWithCleanup(loc, value); + } return SGF.emitManagedRValueWithCleanup(value); } diff --git a/lib/SILGen/Cleanup.h b/lib/SILGen/Cleanup.h index cf8b98df606e3..e2361797d79d6 100644 --- a/lib/SILGen/Cleanup.h +++ b/lib/SILGen/Cleanup.h @@ -84,9 +84,9 @@ class LLVM_LIBRARY_VISIBILITY Cleanup { // // Example: Distinguishing in between @owned cleanups with a writeback buffer // (ExclusiveBorrowCleanup) or ones that involve formal access cleanups. - enum class Flags : uint8_t { + enum Flags : uint8_t { None = 0, - ExclusiveBorrowCleanup = 1, + FormalAccessCleanup = 1, }; private: @@ -95,7 +95,7 @@ class LLVM_LIBRARY_VISIBILITY Cleanup { Flags flags : 8; protected: - Cleanup() {} + Cleanup() : flags(Flags::None) {} virtual ~Cleanup() {} public: @@ -123,6 +123,14 @@ class LLVM_LIBRARY_VISIBILITY Cleanup { virtual bool getWritebackBuffer(function_ref func) { return false; } + + bool isFormalAccess() const { + return getFlags() & Flags::FormalAccessCleanup; + } + + void setIsFormalAccess() { + flags = Flags(flags | Flags::FormalAccessCleanup); + } }; /// A cleanup depth is generally used to denote the set of cleanups @@ -310,9 +318,10 @@ class CleanupStateRestorationScope { /// writeback buffers. class CleanupCloner { SILGenFunction &SGF; + Optional writebackBuffer; bool hasCleanup; bool isLValue; - Optional writebackBuffer; + bool isFormalAccess; public: CleanupCloner(SILGenFunction &SGF, const ManagedValue &mv); diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index 41de4a930cd88..6d89e8e192733 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -1431,10 +1431,12 @@ SILGenFunction::enterDormantTemporaryCleanup(SILValue addr, namespace { -struct FormalAccessReleaseValueCleanup : Cleanup { +struct FormalAccessReleaseValueCleanup final : Cleanup { FormalEvaluationContext::stable_iterator Depth; - FormalAccessReleaseValueCleanup() : Depth() {} + FormalAccessReleaseValueCleanup() : Cleanup(), Depth() { + setIsFormalAccess(); + } void setState(SILGenFunction &SGF, CleanupState newState) override { if (newState == CleanupState::Dead) {