@@ -174,6 +174,15 @@ static bool compatibleOwnershipKinds(ValueOwnershipKind K1,
174
174
return K1.merge (K2).hasValue ();
175
175
}
176
176
177
+ // / Returns true if \p Kind is trivial or if \p Kind is compatible with \p
178
+ // / ComparisonKind.
179
+ static bool
180
+ trivialOrCompatibleOwnershipKinds (ValueOwnershipKind Kind,
181
+ ValueOwnershipKind ComparisonKind) {
182
+ return compatibleOwnershipKinds (Kind, ValueOwnershipKind::Trivial) ||
183
+ compatibleOwnershipKinds (Kind, ComparisonKind);
184
+ }
185
+
177
186
static bool isValueAddressOrTrivial (SILValue V, SILModule &M) {
178
187
return V->getType ().isAddress () ||
179
188
V.getOwnershipKind () == ValueOwnershipKind::Trivial ||
@@ -198,6 +207,7 @@ static bool isOwnershipForwardingValueKind(ValueKind K) {
198
207
case ValueKind::UncheckedEnumDataInst:
199
208
case ValueKind::MarkUninitializedInst:
200
209
case ValueKind::SelectEnumInst:
210
+ case ValueKind::SwitchEnumInst:
201
211
return true ;
202
212
default :
203
213
return false ;
@@ -420,7 +430,6 @@ NO_OPERAND_INST(KeyPath)
420
430
return {compatibleWithOwnership (ValueOwnershipKind::OWNERSHIP), \
421
431
SHOULD_CHECK_FOR_DATAFLOW_VIOLATIONS}; \
422
432
}
423
- CONSTANT_OWNERSHIP_INST (Guaranteed, true , EndBorrowArgument)
424
433
CONSTANT_OWNERSHIP_INST (Guaranteed, false , RefElementAddr)
425
434
CONSTANT_OWNERSHIP_INST(Owned, true , AutoreleaseValue)
426
435
CONSTANT_OWNERSHIP_INST(Owned, true , DeallocBox)
@@ -513,7 +522,6 @@ CONSTANT_OWNERSHIP_INST(Trivial, false, DeallocValueBuffer)
513
522
}
514
523
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST (Owned, true , CheckedCastBranch)
515
524
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true , CheckedCastValueBranch)
516
- CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true , SwitchEnum)
517
525
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true , InitExistentialOpaque)
518
526
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true , DeinitExistentialOpaque)
519
527
#undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST
@@ -655,6 +663,17 @@ FORWARD_CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, false, TupleExtract)
655
663
FORWARD_CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, false , StructExtract)
656
664
#undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST
657
665
666
+ OwnershipUseCheckerResult
667
+ OwnershipCompatibilityUseChecker::visitEndBorrowArgumentInst (EndBorrowArgumentInst *I) {
668
+ // If we are currently checking an end_borrow_argument as a subobject, then we
669
+ // treat this as just a use.
670
+ if (isCheckingSubObject ())
671
+ return {true , false };
672
+
673
+ // Otherwise, we must be checking an actual argument. Make sure it is guaranteed!
674
+ return {true , compatibleWithOwnership (ValueOwnershipKind::Guaranteed)};
675
+ }
676
+
658
677
OwnershipUseCheckerResult
659
678
OwnershipCompatibilityUseChecker::visitSelectEnumInst (SelectEnumInst *I) {
660
679
if (getValue () == I->getEnumOperand ()) {
@@ -724,6 +743,50 @@ OwnershipCompatibilityUseChecker::visitCondBranchInst(CondBranchInst *CBI) {
724
743
getOperandIndex () - FalseOffset);
725
744
}
726
745
746
+ OwnershipUseCheckerResult
747
+ OwnershipCompatibilityUseChecker::visitSwitchEnumInst (SwitchEnumInst *SEI) {
748
+ // If our operand was trivial, return early.
749
+ if (compatibleWithOwnership (ValueOwnershipKind::Trivial))
750
+ return {true , false };
751
+
752
+ // Then we need to go through all of our destinations and make sure that if
753
+ // they have a payload, the payload's convention matches our
754
+ // convention.
755
+ //
756
+ // *NOTE* since we are dealing with enums, we ignore trivial and no payload
757
+ // enums.
758
+ // *NOTE* we assume that all of our types line up and are checked by the
759
+ // normal verifier.
760
+ for (auto *Succ : SEI->getParent ()->getSuccessorBlocks ()) {
761
+ // This must be a no-payload case... continue.
762
+ if (Succ->args_size () == 0 )
763
+ continue ;
764
+
765
+ // If we have a trivial value or a value with ownership kind that matches
766
+ // the switch_enum, then continue.
767
+ auto OwnershipKind = Succ->getArgument (0 )->getOwnershipKind ();
768
+ if (OwnershipKind == ValueOwnershipKind::Trivial ||
769
+ compatibleWithOwnership (OwnershipKind))
770
+ continue ;
771
+
772
+ // Otherwise, emit an error.
773
+ handleError ([&]() {
774
+ llvm::errs ()
775
+ << " Function: '" << Succ->getParent ()->getName () << " '\n "
776
+ << " Error! Argument ownership kind does not match switch_enum!\n "
777
+ << " SwitchEnum: " << *SEI << " Argument: " << *Succ->getArgument (0 )
778
+ << " Expected convention: " << SEI->getOperand ().getOwnershipKind ()
779
+ << " .\n "
780
+ << " Actual convention: " << OwnershipKind << ' \n '
781
+ << ' \n ' ;
782
+ });
783
+ }
784
+
785
+ // Finally, if everything lines up, emit that we match and are a lifetime
786
+ // ending point if we are owned.
787
+ return {true , compatibleWithOwnership (ValueOwnershipKind::Owned)};
788
+ }
789
+
727
790
OwnershipUseCheckerResult
728
791
OwnershipCompatibilityUseChecker::visitReturnInst (ReturnInst *RI) {
729
792
SILModule &M = RI->getModule ();
@@ -1454,8 +1517,8 @@ void SILValueOwnershipChecker::gatherUsers(
1454
1517
// we need to look through subobject uses for more uses. Otherwise, if we are
1455
1518
// forwarding, we do not create any lifetime ending users/non lifetime ending
1456
1519
// users since we verify against our base.
1457
- bool IsGuaranteed =
1458
- Value. getOwnershipKind () == ValueOwnershipKind::Guaranteed;
1520
+ auto OwnershipKind = Value. getOwnershipKind ();
1521
+ bool IsGuaranteed = OwnershipKind == ValueOwnershipKind::Guaranteed;
1459
1522
1460
1523
if (IsGuaranteed && isOwnershipForwardingValue (Value))
1461
1524
return ;
@@ -1512,19 +1575,63 @@ void SILValueOwnershipChecker::gatherUsers(
1512
1575
1513
1576
// At this point, we know that we must have a forwarded subobject. Since the
1514
1577
// base type is guaranteed, we know that the subobject is either guaranteed
1515
- // or trivial. The trivial case is not interesting for ARC verification, so
1516
- // if the user has a trivial ownership kind, continue.
1517
- if (SILValue (User).getOwnershipKind () == ValueOwnershipKind::Trivial) {
1578
+ // or trivial. We now split into two cases, if the user is a terminator or
1579
+ // not. If we do not have a terminator, then just add User->getUses() to the
1580
+ // worklist.
1581
+ auto *TI = dyn_cast<TermInst>(User);
1582
+ if (!TI) {
1583
+ if (SILValue (User).getOwnershipKind () == ValueOwnershipKind::Trivial) {
1584
+ continue ;
1585
+ }
1586
+
1587
+ // Now, we /must/ have a guaranteed subobject, so lets assert that the
1588
+ // user
1589
+ // is actually guaranteed and add the subobject's users to our worklist.
1590
+ assert (SILValue (User).getOwnershipKind () ==
1591
+ ValueOwnershipKind::Guaranteed &&
1592
+ " Our value is guaranteed and this is a forwarding instruction. "
1593
+ " Should have guaranteed ownership as well." );
1594
+ std::copy (User->use_begin (), User->use_end (), std::back_inserter (Users));
1518
1595
continue ;
1519
1596
}
1520
1597
1521
- // Now, we /must/ have a guaranteed subobject, so lets assert that the user
1522
- // is actually guaranteed and add the subobject's users to our worklist.
1523
- assert (SILValue (User).getOwnershipKind () ==
1524
- ValueOwnershipKind::Guaranteed &&
1525
- " Our value is guaranteed and this is a forwarding instruction. "
1526
- " Should have guaranteed ownership as well." );
1527
- std::copy (User->use_begin (), User->use_end (), std::back_inserter (Users));
1598
+ // Otherwise if we have a terminator, add any as uses any
1599
+ // end_borrow_argument to ensure that the subscope is completely enclsed
1600
+ // within the super scope. all of the arguments to the work list. We require
1601
+ // all of our arguments to be either trivial or guaranteed.
1602
+ for (auto &Succ : TI->getSuccessors ()) {
1603
+ auto *BB = Succ.getBB ();
1604
+
1605
+ // If we do not have any arguments, then continue.
1606
+ if (BB->args_empty ())
1607
+ continue ;
1608
+
1609
+ // Otherwise, make sure that all arguments are trivial or guaranteed. If
1610
+ // we fail, emit an error.
1611
+ //
1612
+ // TODO: We could ignore this error and emit a more specific error on the
1613
+ // actual terminator.
1614
+ for (auto *BBArg : BB->getArguments ()) {
1615
+ // *NOTE* We do not emit an error here since we want to allow for more
1616
+ // specific errors to be found during use_verification.
1617
+ //
1618
+ // TODO: Add a flag that associates the terminator instruction with
1619
+ // needing to be verified. If it isn't verified appropriately, assert
1620
+ // when the verifier is destroyed.
1621
+ if (!trivialOrCompatibleOwnershipKinds (BBArg->getOwnershipKind (),
1622
+ OwnershipKind)) {
1623
+ // This is where the error would go.
1624
+ continue ;
1625
+ }
1626
+
1627
+ // If we have a trivial value, just continue.
1628
+ if (BBArg->getOwnershipKind () == ValueOwnershipKind::Trivial)
1629
+ continue ;
1630
+
1631
+ // Otherwise,
1632
+ std::copy (BBArg->use_begin (), BBArg->use_end (), std::back_inserter (Users));
1633
+ }
1634
+ }
1528
1635
}
1529
1636
}
1530
1637
0 commit comments