1313#define DEBUG_TYPE " sil-ownership-verifier"
1414
1515#include " LinearLifetimeCheckerPrivate.h"
16+
1617#include " swift/AST/ASTContext.h"
1718#include " swift/AST/AnyFunctionRef.h"
1819#include " swift/AST/Decl.h"
3233#include " swift/SIL/SILBuiltinVisitor.h"
3334#include " swift/SIL/SILDebugScope.h"
3435#include " swift/SIL/SILFunction.h"
36+ #include " swift/SIL/SILInstruction.h"
3537#include " swift/SIL/SILModule.h"
3638#include " swift/SIL/SILOpenedArchetypesTracker.h"
3739#include " swift/SIL/SILVTable.h"
3840#include " swift/SIL/SILVisitor.h"
3941#include " swift/SIL/TypeLowering.h"
42+
4043#include " llvm/ADT/DenseSet.h"
4144#include " llvm/ADT/PostOrderIterator.h"
45+ #include " llvm/ADT/SmallVector.h"
4246#include " llvm/ADT/StringSet.h"
4347#include " llvm/Support/CommandLine.h"
4448#include " llvm/Support/Debug.h"
49+
4550#include < algorithm>
4651
4752using namespace swift ;
@@ -130,10 +135,11 @@ class SILValueOwnershipChecker {
130135 bool gatherNonGuaranteedUsers (SmallVectorImpl<Operand *> &lifetimeEndingUsers,
131136 SmallVectorImpl<Operand *> ®ularUsers);
132137
133- bool checkValueWithoutLifetimeEndingUses ();
138+ bool checkValueWithoutLifetimeEndingUses (ArrayRef<Operand *> regularUsers );
134139
135140 bool checkFunctionArgWithoutLifetimeEndingUses (SILFunctionArgument *arg);
136- bool checkYieldWithoutLifetimeEndingUses (BeginApplyResult *yield);
141+ bool checkYieldWithoutLifetimeEndingUses (BeginApplyResult *yield,
142+ ArrayRef<Operand *> regularUsers);
137143
138144 bool isGuaranteedFunctionArgWithLifetimeEndingUses (
139145 SILFunctionArgument *arg,
@@ -501,25 +507,56 @@ bool SILValueOwnershipChecker::checkFunctionArgWithoutLifetimeEndingUses(
501507}
502508
503509bool SILValueOwnershipChecker::checkYieldWithoutLifetimeEndingUses (
504- BeginApplyResult *yield) {
510+ BeginApplyResult *yield, ArrayRef<Operand *> regularUses ) {
505511 switch (yield->getOwnershipKind ()) {
506- case ValueOwnershipKind::Guaranteed:
507512 case ValueOwnershipKind::Unowned:
508513 case ValueOwnershipKind::None:
509514 return true ;
510515 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.
511530 break ;
512531 }
513532
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 ;
515550 return true ;
551+ }
516552
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 ;
521556}
522- bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses () {
557+
558+ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses (
559+ ArrayRef<Operand *> regularUses) {
523560 LLVM_DEBUG (llvm::dbgs () << " No lifetime ending users?! Bailing early.\n " );
524561 if (auto *arg = dyn_cast<SILFunctionArgument>(value)) {
525562 if (checkFunctionArgWithoutLifetimeEndingUses (arg)) {
@@ -528,9 +565,7 @@ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses() {
528565 }
529566
530567 if (auto *yield = dyn_cast<BeginApplyResult>(value)) {
531- if (checkYieldWithoutLifetimeEndingUses (yield)) {
532- return true ;
533- }
568+ return checkYieldWithoutLifetimeEndingUses (yield, regularUses);
534569 }
535570
536571 // Check if we are a guaranteed subobject. In such a case, we should never
@@ -622,6 +657,7 @@ bool SILValueOwnershipChecker::checkUses() {
622657 // 1. A trivial typed value.
623658 // 2. An address type value.
624659 // 3. A guaranteed function argument.
660+ // 4. A yielded guaranteed value.
625661 //
626662 // In the first two cases, it is easy to see that there is nothing further to
627663 // do but return false.
@@ -630,8 +666,13 @@ bool SILValueOwnershipChecker::checkUses() {
630666 // more. Specifically, we should have /no/ lifetime ending uses of a
631667 // guaranteed function argument, since a guaranteed function argument should
632668 // 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 ;
635676 }
636677
637678 LLVM_DEBUG (llvm::dbgs () << " Found lifetime ending users! Performing "
0 commit comments