13
13
#define DEBUG_TYPE "sil-ownership-verifier"
14
14
15
15
#include "LinearLifetimeCheckerPrivate.h"
16
+
16
17
#include "swift/AST/ASTContext.h"
17
18
#include "swift/AST/AnyFunctionRef.h"
18
19
#include "swift/AST/Decl.h"
32
33
#include "swift/SIL/SILBuiltinVisitor.h"
33
34
#include "swift/SIL/SILDebugScope.h"
34
35
#include "swift/SIL/SILFunction.h"
36
+ #include "swift/SIL/SILInstruction.h"
35
37
#include "swift/SIL/SILModule.h"
36
38
#include "swift/SIL/SILOpenedArchetypesTracker.h"
37
39
#include "swift/SIL/SILVTable.h"
38
40
#include "swift/SIL/SILVisitor.h"
39
41
#include "swift/SIL/TypeLowering.h"
42
+
40
43
#include "llvm/ADT/DenseSet.h"
41
44
#include "llvm/ADT/PostOrderIterator.h"
45
+ #include "llvm/ADT/SmallVector.h"
42
46
#include "llvm/ADT/StringSet.h"
43
47
#include "llvm/Support/CommandLine.h"
44
48
#include "llvm/Support/Debug.h"
49
+
45
50
#include <algorithm>
46
51
47
52
using namespace swift;
@@ -130,10 +135,11 @@ class SILValueOwnershipChecker {
130
135
bool gatherNonGuaranteedUsers(SmallVectorImpl<Operand *> &lifetimeEndingUsers,
131
136
SmallVectorImpl<Operand *> ®ularUsers);
132
137
133
- bool checkValueWithoutLifetimeEndingUses ();
138
+ bool checkValueWithoutLifetimeEndingUses(ArrayRef<Operand *> regularUsers );
134
139
135
140
bool checkFunctionArgWithoutLifetimeEndingUses(SILFunctionArgument *arg);
136
- bool checkYieldWithoutLifetimeEndingUses (BeginApplyResult *yield);
141
+ bool checkYieldWithoutLifetimeEndingUses(BeginApplyResult *yield,
142
+ ArrayRef<Operand *> regularUsers);
137
143
138
144
bool isGuaranteedFunctionArgWithLifetimeEndingUses(
139
145
SILFunctionArgument *arg,
@@ -501,25 +507,56 @@ bool SILValueOwnershipChecker::checkFunctionArgWithoutLifetimeEndingUses(
501
507
}
502
508
503
509
bool SILValueOwnershipChecker::checkYieldWithoutLifetimeEndingUses(
504
- BeginApplyResult *yield) {
510
+ BeginApplyResult *yield, ArrayRef<Operand *> regularUses ) {
505
511
switch (yield->getOwnershipKind()) {
506
- case ValueOwnershipKind::Guaranteed:
507
512
case ValueOwnershipKind::Unowned:
508
513
case ValueOwnershipKind::None:
509
514
return true;
510
515
case ValueOwnershipKind::Owned:
516
+ if (deadEndBlocks.isDeadEnd(yield->getParent()->getParent()))
517
+ return true;
518
+
519
+ return !errorBuilder.handleMalformedSIL([&] {
520
+ llvm::errs() << "Owned yield without life ending uses!\n"
521
+ << "Value: " << *yield << '\n';
522
+ });
523
+ case ValueOwnershipKind::Guaranteed:
524
+ // NOTE: If we returned false here, we would catch any error caught below as
525
+ // an out of lifetime use of the yielded value. That being said, that would
526
+ // be confusing from a code perspective since we would be validating
527
+ // something that did not have a /real/ lifetime ending use (one could
528
+ // consider the end_apply to be a pseudo-lifetime ending uses) along a code
529
+ // path that is explicitly trying to do that.
511
530
break;
512
531
}
513
532
514
- if (deadEndBlocks.isDeadEnd (yield->getParent ()->getParent ()))
533
+ // If we have a guaranteed value, make sure that all uses are before our
534
+ // end_yield.
535
+ SmallVector<Operand *, 4> coroutineEndUses;
536
+ for (auto *use : yield->getParent()->getTokenResult()->getUses()) {
537
+ coroutineEndUses.push_back(use);
538
+ }
539
+
540
+ assert(visitedBlocks.empty());
541
+ LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks);
542
+ auto linearLifetimeResult =
543
+ checker.checkValue(yield, coroutineEndUses, regularUses, errorBuilder);
544
+ if (linearLifetimeResult.getFoundError()) {
545
+ // We return true here even if we find an error since we want to only emit
546
+ // this error for the value rather than continue and go down the "has
547
+ // consuming use" path. This is to work around any confusion that maybe
548
+ // caused by end_apply/abort_apply acting as a pseudo-ending lifetime use.
549
+ result = true;
515
550
return true;
551
+ }
516
552
517
- return !errorBuilder.handleMalformedSIL ([&] {
518
- llvm::errs () << " Owned yield without life ending uses!\n "
519
- << " Value: " << *yield << ' \n ' ;
520
- });
553
+ // Otherwise, we do not set result to have a value and return since all of our
554
+ // guaranteed value's uses are appropriate.
555
+ return true;
521
556
}
522
- bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses () {
557
+
558
+ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses(
559
+ ArrayRef<Operand *> regularUses) {
523
560
LLVM_DEBUG(llvm::dbgs() << "No lifetime ending users?! Bailing early.\n");
524
561
if (auto *arg = dyn_cast<SILFunctionArgument>(value)) {
525
562
if (checkFunctionArgWithoutLifetimeEndingUses(arg)) {
@@ -528,9 +565,7 @@ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses() {
528
565
}
529
566
530
567
if (auto *yield = dyn_cast<BeginApplyResult>(value)) {
531
- if (checkYieldWithoutLifetimeEndingUses (yield)) {
532
- return true ;
533
- }
568
+ return checkYieldWithoutLifetimeEndingUses(yield, regularUses);
534
569
}
535
570
536
571
// Check if we are a guaranteed subobject. In such a case, we should never
@@ -622,6 +657,7 @@ bool SILValueOwnershipChecker::checkUses() {
622
657
// 1. A trivial typed value.
623
658
// 2. An address type value.
624
659
// 3. A guaranteed function argument.
660
+ // 4. A yielded guaranteed value.
625
661
//
626
662
// In the first two cases, it is easy to see that there is nothing further to
627
663
// do but return false.
@@ -630,8 +666,13 @@ bool SILValueOwnershipChecker::checkUses() {
630
666
// more. Specifically, we should have /no/ lifetime ending uses of a
631
667
// guaranteed function argument, since a guaranteed function argument should
632
668
// outlive the current function always.
633
- if (lifetimeEndingUsers.empty () && checkValueWithoutLifetimeEndingUses ()) {
634
- return false ;
669
+ //
670
+ // In the case of a yielded guaranteed value, we need to validate that all
671
+ // regular uses of the value are within the co
672
+ if (lifetimeEndingUsers.empty()) {
673
+ if (checkValueWithoutLifetimeEndingUses(regularUsers))
674
+ return false;
675
+ return true;
635
676
}
636
677
637
678
LLVM_DEBUG(llvm::dbgs() << " Found lifetime ending users! Performing "
0 commit comments