//===--- ReborrowVerifier.cpp ---------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-reborrow-checker" #include "ReborrowVerifierPrivate.h" using namespace swift; bool ReborrowVerifier::verifyReborrowLifetime(SILPhiArgument *phiArg, SILValue baseVal) { SmallPtrSet visitedBlocks; bool result = false; SmallVector phiArgUses(phiArg->getUses()); // Verify whether the guaranteed phi arg lies within the lifetime of the base // value. LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); // newErrorBuilder is consumed at the end of the checkValue function. // Copy initial state from errorBuilder everytime LinearLifetimeChecker::ErrorBuilder newErrorBuilder = errorBuilder; SmallVector baseValConsumingUses(baseVal->getConsumingUses()); // If the baseValue has no consuming uses, there is nothing more to verify if (baseValConsumingUses.empty()) return false; auto linearLifetimeResult = checker.checkValue(baseVal, baseValConsumingUses, phiArgUses, newErrorBuilder); result |= linearLifetimeResult.getFoundError(); return result; } void ReborrowVerifier::verifyReborrows(BorrowingOperand initialScopedOperand, SILValue value) { SmallVector, 4> worklist; // Initialize the worklist with borrow lifetime ending uses initialScopedOperand.visitLocalEndScopeUses([&](Operand *op) { worklist.emplace_back(op, value); return true; }); while (!worklist.empty()) { Operand *borrowLifetimeEndOp; SILValue baseVal; std::tie(borrowLifetimeEndOp, baseVal) = worklist.pop_back_val(); auto *borrowLifetimeEndUser = borrowLifetimeEndOp->getUser(); auto borrowingOperand = BorrowingOperand::get(borrowLifetimeEndOp); if (!borrowingOperand || !borrowingOperand->isReborrow()) continue; if (isVisitedOp(borrowLifetimeEndOp, baseVal)) continue; // Process reborrow auto *branchInst = cast(borrowLifetimeEndUser); for (auto *succBlock : branchInst->getSuccessorBlocks()) { auto *phiArg = cast( succBlock->getArgument(borrowLifetimeEndOp->getOperandNumber())); assert(phiArg->getOwnershipKind() == OwnershipKind::Guaranteed); SILValue newBaseVal = baseVal; // If the previous base value was also passed as a phi arg, that will be // the new base value. for (auto *arg : succBlock->getArguments()) { if (arg->getIncomingPhiValue(branchInst->getParent()) == baseVal) { newBaseVal = arg; break; } } if (isVisitedPhiArg(phiArg, newBaseVal)) continue; addVisitedPhiArg(phiArg, newBaseVal); verifyReborrowLifetime(phiArg, newBaseVal); // Find the scope ending uses of the guaranteed phi arg and add it to the // worklist. auto scopedValue = BorrowedValue::get(phiArg); assert(scopedValue.hasValue()); scopedValue->visitLocalScopeEndingUses([&](Operand *op) { addVisitedOp(op, newBaseVal); worklist.emplace_back(op, newBaseVal); }); } } }