8888// alloc_stack %stack
8989// %elem1borrow = begin_borrow %elem1copy
9090// store_borrow %elem1borrow to %stack
91- // end_borrow %elem1borrow
9291// try_apply %body(%stack) normal normalbb1, error errbb1
9392//
9493// errbb1(%error : @owned $Error):
95- // br bb2(%error)
94+ // end_borrow %elem1borrow
95+ // br bb2(%error)
9696//
9797// normalbb1(%res : $()):
98+ // end_borrow %elem1borrow
9899// %elem2borrow = begin_borrow %elem2copy
99100// store_borrow %elem2borrow to %stack
100- // end_borrow %elem2borrow
101101// try_apply %body(%stack) normal bb1, error errbb2
102102//
103103// errbb2(%error : @owned $Error):
104- // br bb2(%error)
104+ // end_borrow %elem2borrow
105+ // br bb2(%error)
105106//
106107// bb1(%res : $()):
108+ // end_borrow %elem2borrow
107109// dealloc_stack %stack
108110// ...
109111// bb2(%error : @owned $Error):
@@ -499,12 +501,16 @@ static void unrollForEach(ArrayInfo &arrayInfo, TryApplyInst *forEachCall,
499501 // A generator for creating a basic block for use as the target of the
500502 // "error" branch of a try_apply. The error block created here will always
501503 // jump to the error target of the original forEach.
502- auto errorTargetGenerator = [&](SILBasicBlock *insertionBlock) {
504+ auto errorTargetGenerator = [&](SILBasicBlock *insertionBlock,
505+ SILValue borrowedElem ) {
503506 SILBasicBlock *newErrorBB = fun->createBasicBlockBefore (insertionBlock);
504507 SILValue argument = newErrorBB->createPhiArgument (
505508 errorArgument->getType (), errorArgument->getOwnershipKind ());
506509 // Make the errorBB jump to the error target of the original forEach.
507510 SILBuilderWithScope builder (newErrorBB, forEachCall);
511+ if (borrowedElem) {
512+ builder.createEndBorrow (forEachLoc, borrowedElem);
513+ }
508514 builder.createBranch (forEachLoc, errorBB, argument);
509515 return newErrorBB;
510516 };
@@ -525,28 +531,34 @@ static void unrollForEach(ArrayInfo &arrayInfo, TryApplyInst *forEachCall,
525531 // error blocks jump to the error target of the original forEach call.
526532 for (uint64_t num = arrayInfo.getNumElements (); num > 0 ; --num) {
527533 SILValue elementCopy = elementCopies[num - 1 ];
534+ // Creating the next normal block ends the borrow scope for borrowedElem
535+ // from the previous iteration.
528536 SILBasicBlock *currentBB = num > 1 ? normalTargetGenerator (nextNormalBB)
529537 : forEachCall->getParentBlock ();
530538 SILBuilderWithScope unrollBuilder (currentBB, forEachCall);
539+ SILValue borrowedElem;
531540 if (arrayElementType.isTrivial (*fun)) {
532541 unrollBuilder.createStore (forEachLoc, elementCopy, allocStack,
533542 StoreOwnershipQualifier::Trivial);
534543 } else {
535544 // Borrow the elementCopy and store it in the allocStack. Note that the
536545 // element's copy is guaranteed to be alive until the array is alive.
537546 // Therefore it is okay to use a borrow here.
538- SILValue borrowedElem =
539- unrollBuilder.createBeginBorrow (forEachLoc, elementCopy);
547+ borrowedElem = unrollBuilder.createBeginBorrow (forEachLoc, elementCopy);
540548 unrollBuilder.createStoreBorrow (forEachLoc, borrowedElem, allocStack);
541- unrollBuilder.createEndBorrow (forEachLoc, borrowedElem);
549+
550+ SILBuilderWithScope (&nextNormalBB->front (), forEachCall)
551+ .createEndBorrow (forEachLoc, borrowedElem);
542552 }
543- SILBasicBlock *errorTarget = errorTargetGenerator (nextNormalBB);
553+
554+ SILBasicBlock *errorTarget =
555+ errorTargetGenerator (nextNormalBB, borrowedElem);
544556 // Note that the substitution map must be empty as we are not supporting
545557 // elements of address-only type. All elements in the array are guaranteed
546558 // to be loadable. TODO: generalize this to address-only types.
547559 unrollBuilder.createTryApply (forEachLoc, forEachBodyClosure,
548- SubstitutionMap (), allocStack, nextNormalBB,
549- errorTarget);
560+ SubstitutionMap (), allocStack,
561+ nextNormalBB, errorTarget);
550562 nextNormalBB = currentBB;
551563 }
552564
0 commit comments