Files
swift-mirror/lib/SIL/Verifier/ReborrowVerifierPrivate.h
Meghana Gupta 601ea65b5d [ownership] Add a new ReborrowVerifier
This updates how we model reborrow's lifetimes for ownership verification.
Today we follow and combine a borrow's lifetime through phi args as well.
Owned values lifetimes end at a phi arg. This discrepency in modeling
lifetimes leads to the OwnershipVerifier raising errors incorrectly for
cases such as this, where the borrow and the base value do not dominate
the end_borrow:

bb0:
  cond_br undef, bb1, bb2
bb1:
  %copy0 = copy_value %0
  %borrow0 = begin_borrow %copy0
  br bb3(%borrow0, %copy0)
bb2:
  %copy1 = copy_value %1
  %borrow1 = begin_borrow %copy1
  br bb3(%borrow1, %copy1)
bb3(%borrow, %baseVal):
  end_borrow %borrow
  destroy_value %baseVal

This PR adds a new ReborrowVerifier. The ownership verifier collects borrow's
lifetime ending users and populates the worklist of the ReborrowVerifier
with reborrows and the corresponding base value.
ReborrowVerifier then verifies that the lifetime of the reborrow is
within the lifetime of the base value.
2020-10-29 20:46:37 -07:00

78 lines
2.7 KiB
C++

//===--- ReborrowVerifierPrivate.h ----------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 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
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SIL_REBORROWVERIFIER_H
#define SWIFT_SIL_REBORROWVERIFIER_H
#include "LinearLifetimeCheckerPrivate.h"
#include "swift/SIL/OwnershipUtils.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILValue.h"
namespace swift {
class DeadEndBlocks;
/// A guaranteed phi arg ends the borrow scope of its incoming value and begins
/// a new borrow scope. ReborrowVerifier validates the lifetime of the reborrow
/// lies within the lifetime of its base value. It uses LinearLifetimeChecker
/// for this.
class ReborrowVerifier {
/// A cache of dead-end basic blocks that we use to determine if we can
/// ignore "leaks".
DeadEndBlocks &deadEndBlocks;
/// A cache map of borrow lifetime ending operands and their base value
llvm::SmallDenseMap<Operand *, SILValue> visitedOps;
/// A cache map of guaranteed phi args and their base value
llvm::SmallDenseMap<SILPhiArgument *, SILValue> visitedPhiArgs;
/// The builder that the checker uses to emit error messages, crash if asked
/// for, or supply back interesting info to the caller.
LinearLifetimeChecker::ErrorBuilder errorBuilder;
public:
ReborrowVerifier(const SILFunction *func, DeadEndBlocks &deadEndBlocks,
LinearLifetimeChecker::ErrorBuilder errorBuilder)
: deadEndBlocks(deadEndBlocks), errorBuilder(errorBuilder) {}
void verifyReborrows(BorrowingOperand initialScopedOperand, SILValue value);
private:
/// Verifies whether the reborrow's lifetime lies within its base value
bool verifyReborrowLifetime(SILPhiArgument *phiArg, SILValue baseVal);
/// Check if the operand is visited
bool isVisitedOp(Operand *op, SILValue baseVal) {
return visitedOps.find(op) != visitedOps.end();
}
/// Check if the phi arg and base value are visited
bool isVisitedPhiArg(SILPhiArgument *phiArg, SILValue baseVal) {
auto itPhiArg = visitedPhiArgs.find(phiArg);
return itPhiArg != visitedPhiArgs.end() && (*itPhiArg).second == baseVal;
}
/// Mark operand as visited
void addVisitedOp(Operand *op, SILValue baseVal) {
visitedOps.insert({op, baseVal});
}
/// Mark guaranteed phi arg as visited
void addVisitedPhiArg(SILPhiArgument *phiArg, SILValue baseVal) {
visitedPhiArgs.insert({phiArg, baseVal});
}
};
} // namespace swift
#endif