@@ -98,6 +98,8 @@ static bool isOwnershipForwardingValueKind(SILNodeKind K) {
9898 case SILNodeKind::SelectEnumInst:
9999 case SILNodeKind::SwitchEnumInst:
100100 case SILNodeKind::CheckedCastBranchInst:
101+ case SILNodeKind::BranchInst:
102+ case SILNodeKind::CondBranchInst:
101103 case SILNodeKind::DestructureStructInst:
102104 case SILNodeKind::DestructureTupleInst:
103105 return true ;
@@ -795,6 +797,16 @@ OwnershipCompatibilityUseChecker::visitReturnInst(ReturnInst *RI) {
795797
796798OwnershipUseCheckerResult
797799OwnershipCompatibilityUseChecker::visitEndBorrowInst (EndBorrowInst *I) {
800+ // If we are checking a subobject, make sure that we are from a guaranteed
801+ // basic block argument.
802+ if (isCheckingSubObject ()) {
803+ auto *phiArg = cast<SILPHIArgument>(Op.get ());
804+ (void )phiArg;
805+ assert (phiArg->getOwnershipKind () == ValueOwnershipKind::Guaranteed &&
806+ " Expected an end_borrow paired with an argument." );
807+ return {true , UseLifetimeConstraint::MustBeLive};
808+ }
809+
798810 // / An end_borrow is modeled as invalidating the guaranteed value preventing
799811 // / any further uses of the value.
800812 return {compatibleWithOwnership (ValueOwnershipKind::Guaranteed),
@@ -1438,6 +1450,7 @@ void SILValueOwnershipChecker::gatherUsers(
14381450 // users since we verify against our base.
14391451 auto OwnershipKind = Value.getOwnershipKind ();
14401452 bool IsGuaranteed = OwnershipKind == ValueOwnershipKind::Guaranteed;
1453+ bool IsOwned = OwnershipKind == ValueOwnershipKind::Owned;
14411454
14421455 if (IsGuaranteed && isGuaranteedForwardingValue (Value))
14431456 return ;
@@ -1485,27 +1498,37 @@ void SILValueOwnershipChecker::gatherUsers(
14851498 }
14861499 }
14871500
1488- // If our base value is not guaranteed or our intermediate value is not an
1489- // ownership forwarding inst, continue. We do not want to visit any
1490- // subobjects recursively.
1491- if (!IsGuaranteed || !isGuaranteedForwardingInst (User)) {
1492- // Do a check if any of our users are begin_borrows. If we find such a
1493- // use, then we want to include the end_borrow associated with the
1494- // begin_borrow in our NonLifetimeEndingUser lists.
1495- //
1496- // For correctness reasons we use indices to make sure that we can append
1497- // to NonLifetimeEndingUsers without needing to deal with iterator
1498- // invalidation.
1499- SmallVector<SILInstruction *, 4 > endBorrowInsts;
1500- for (unsigned i : indices (NonLifetimeEndingUsers)) {
1501- if (auto *bbi = dyn_cast<BeginBorrowInst>(
1502- NonLifetimeEndingUsers[i].getInst ())) {
1503- copy (bbi->getEndBorrows (), std::back_inserter (ImplicitRegularUsers));
1501+ // If our base value is not guaranteed, we do not to try to visit
1502+ // subobjects.
1503+ if (!IsGuaranteed) {
1504+ // But if we are owned, check if we have any end_borrows. We
1505+ // need to treat these as sub-scope users. We can rely on the
1506+ // end_borrow to prevent recursion.
1507+ if (IsOwned) {
1508+ // Do a check if any of our users are begin_borrows. If we find such a
1509+ // use, then we want to include the end_borrow associated with the
1510+ // begin_borrow in our NonLifetimeEndingUser lists.
1511+ //
1512+ // For correctness reasons we use indices to make sure that we can
1513+ // append to NonLifetimeEndingUsers without needing to deal with
1514+ // iterator invalidation.
1515+ SmallVector<SILInstruction *, 4 > endBorrowInsts;
1516+ for (unsigned i : indices (NonLifetimeEndingUsers)) {
1517+ if (auto *bbi = dyn_cast<BeginBorrowInst>(
1518+ NonLifetimeEndingUsers[i].getInst ())) {
1519+ copy (bbi->getEndBorrows (),
1520+ std::back_inserter (ImplicitRegularUsers));
1521+ }
15041522 }
15051523 }
15061524 continue ;
15071525 }
15081526
1527+ // If we are guaranteed, but are not a guaranteed forwarding inst,
1528+ // just continue. This user is just treated as a normal use.
1529+ if (!isGuaranteedForwardingInst (User))
1530+ continue ;
1531+
15091532 // At this point, we know that we must have a forwarded subobject. Since the
15101533 // base type is guaranteed, we know that the subobject is either guaranteed
15111534 // or trivial. We now split into two cases, if the user is a terminator or
@@ -1537,9 +1560,8 @@ void SILValueOwnershipChecker::gatherUsers(
15371560 }
15381561
15391562 // Otherwise if we have a terminator, add any as uses any end_borrow to
1540- // ensure that the subscope is completely enclsed within the super
1541- // scope. all of the arguments to the work list. We require all of our
1542- // arguments to be either trivial or guaranteed.
1563+ // ensure that the subscope is completely enclsed within the super scope. We
1564+ // require all of our arguments to be either trivial or guaranteed.
15431565 for (auto &Succ : TI->getSuccessors ()) {
15441566 auto *BB = Succ.getBB ();
15451567
@@ -1552,7 +1574,7 @@ void SILValueOwnershipChecker::gatherUsers(
15521574 //
15531575 // TODO: We could ignore this error and emit a more specific error on the
15541576 // actual terminator.
1555- for (auto *BBArg : BB->getArguments ()) {
1577+ for (auto *BBArg : BB->getPHIArguments ()) {
15561578 // *NOTE* We do not emit an error here since we want to allow for more
15571579 // specific errors to be found during use_verification.
15581580 //
@@ -1569,8 +1591,16 @@ void SILValueOwnershipChecker::gatherUsers(
15691591 if (BBArgOwnershipKind == ValueOwnershipKind::Trivial)
15701592 continue ;
15711593
1572- // Otherwise,
1573- copy (BBArg->getUses (), std::back_inserter (Users));
1594+ // Otherwise add all end_borrow users for this BBArg to the
1595+ // implicit regular user list. We know that BBArg must be
1596+ // completely joint post-dominated by these users, so we use
1597+ // them to ensure that all of BBArg's uses are completely
1598+ // enclosed within the end_borrow of this argument.
1599+ for (auto *op : BBArg->getUses ()) {
1600+ if (auto *ebi = dyn_cast<EndBorrowInst>(op->getUser ())) {
1601+ ImplicitRegularUsers.push_back (ebi);
1602+ }
1603+ }
15741604 }
15751605 }
15761606 }
0 commit comments