Skip to content

Commit c4bdc97

Browse files
committed
SILGen: Separate borrow from consume phase for destructive pattern matches.
We don't want the dispatch phase of a pattern match to invalidate the subject, because we don't define the order in which patterns are evaluated, and if a particular match attempt fails, we need to still have an intact subject value on hand to try a potentially arbitrary other pattern against it. For noncopyable types, this means we have to always emit the match phase as a borrow, including the variable bindings for a guard expression if any. For a consuming pattern match, end the borrow scope and reproject the variable bindings by using consuming destructuring operations on the subject in the match block. For now, this new code path only handles single-case-label-per-block switches without fallthroughs.
1 parent 960938f commit c4bdc97

File tree

4 files changed

+457
-25
lines changed

4 files changed

+457
-25
lines changed

lib/SILGen/Cleanup.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@ void CleanupManager::endScope(CleanupsDepth depth, CleanupLocation loc) {
142142
emitCleanups(depth, loc, NotForUnwind, /*popCleanups*/ true);
143143
}
144144

145+
/// Leave a scope, emitting all the cleanups that are currently active but leaving them on the stack so they
146+
/// can be reenabled on other pattern match branches.
147+
void CleanupManager::endNoncopyablePatternMatchBorrow(CleanupsDepth depth,
148+
CleanupLocation loc,
149+
bool popCleanups) {
150+
emitCleanups(depth, loc, NotForUnwind, popCleanups);
151+
}
152+
145153
bool CleanupManager::hasAnyActiveCleanups(CleanupsDepth from,
146154
CleanupsDepth to) {
147155
return ::hasAnyActiveCleanups(stack.find(from), stack.find(to));

lib/SILGen/Cleanup.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ typedef DiverseStackImpl<Cleanup>::stable_iterator CleanupHandle;
159159
class LLVM_LIBRARY_VISIBILITY CleanupManager {
160160
friend class Scope;
161161
friend class CleanupCloner;
162-
162+
163163
SILGenFunction &SGF;
164164

165165
/// Stack - Currently active cleanups in this scope tree.
@@ -289,6 +289,9 @@ class LLVM_LIBRARY_VISIBILITY CleanupManager {
289289
/// Verify that the given cleanup handle is valid.
290290
void checkIterator(CleanupHandle handle) const;
291291

292+
void endNoncopyablePatternMatchBorrow(CleanupsDepth depth, CleanupLocation l,
293+
bool finalEndBorrow = false);
294+
292295
private:
293296
// Look up the flags and optionally the writeback address associated with the
294297
// cleanup at \p depth. If

lib/SILGen/ManagedValue.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,9 @@ class ConsumableManagedValue {
520520

521521
/// Return a managed value that's appropriate for borrowing this
522522
/// value and promising not to consume it.
523+
///
524+
/// TODO: Should be superseded by `asBorrowedOperand2` once existing code is
525+
/// updated to tolerate address-only values being borrowed.
523526
ConsumableManagedValue asBorrowedOperand(SILGenFunction &SGF,
524527
SILLocation loc) const {
525528
if (getType().isAddress())
@@ -532,6 +535,18 @@ class ConsumableManagedValue {
532535
CastConsumptionKind::BorrowAlways};
533536
}
534537

538+
ConsumableManagedValue asBorrowedOperand2(SILGenFunction &SGF,
539+
SILLocation loc) const {
540+
if (getType().isAddress())
541+
return {asUnmanagedOwnedValue(), CastConsumptionKind::BorrowAlways};
542+
543+
if (Value.getOwnershipKind() == OwnershipKind::Guaranteed)
544+
return {Value, CastConsumptionKind::BorrowAlways};
545+
546+
return {asUnmanagedOwnedValue().borrow(SGF, loc),
547+
CastConsumptionKind::BorrowAlways};
548+
}
549+
535550
/// Return a managed value that's appropriate for copying this value and
536551
/// always consuming it.
537552
ConsumableManagedValue copy(SILGenFunction &SGF, SILLocation loc) const {

0 commit comments

Comments
 (0)