150 lines
5.0 KiB
C++
150 lines
5.0 KiB
C++
//===- Loans.h - Loan and Access Path Definitions --------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the Loan and AccessPath structures, which represent
|
|
// borrows of storage locations, and the LoanManager, which manages the
|
|
// creation and retrieval of loans during lifetime analysis.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LOANS_H
|
|
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LOANS_H
|
|
|
|
#include "clang/AST/Decl.h"
|
|
#include "clang/Analysis/Analyses/LifetimeSafety/Utils.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
namespace clang::lifetimes::internal {
|
|
|
|
using LoanID = utils::ID<struct LoanTag>;
|
|
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, LoanID ID) {
|
|
return OS << ID.Value;
|
|
}
|
|
|
|
/// Represents the storage location being borrowed, e.g., a specific stack
|
|
/// variable.
|
|
/// TODO: Model access paths of other types, e.g., s.field, heap and globals.
|
|
struct AccessPath {
|
|
const clang::ValueDecl *D;
|
|
|
|
AccessPath(const clang::ValueDecl *D) : D(D) {}
|
|
};
|
|
|
|
/// An abstract base class for a single "Loan" which represents lending a
|
|
/// storage in memory.
|
|
class Loan {
|
|
/// TODO: Represent opaque loans.
|
|
/// TODO: Represent nullptr: loans to no path. Accessing it UB! Currently it
|
|
/// is represented as empty LoanSet
|
|
public:
|
|
enum class Kind : uint8_t {
|
|
/// A loan with an access path to a storage location.
|
|
Path,
|
|
/// A non-expiring placeholder loan for a parameter, representing a borrow
|
|
/// from the function's caller.
|
|
Placeholder
|
|
};
|
|
|
|
Loan(Kind K, LoanID ID) : K(K), ID(ID) {}
|
|
virtual ~Loan() = default;
|
|
|
|
Kind getKind() const { return K; }
|
|
LoanID getID() const { return ID; }
|
|
|
|
virtual void dump(llvm::raw_ostream &OS) const = 0;
|
|
|
|
private:
|
|
const Kind K;
|
|
const LoanID ID;
|
|
};
|
|
|
|
/// PathLoan represents lending a storage location that is visible within the
|
|
/// function's scope (e.g., a local variable on stack).
|
|
class PathLoan : public Loan {
|
|
AccessPath Path;
|
|
/// The expression that creates the loan, e.g., &x.
|
|
const Expr *IssueExpr;
|
|
|
|
public:
|
|
PathLoan(LoanID ID, AccessPath Path, const Expr *IssueExpr)
|
|
: Loan(Kind::Path, ID), Path(Path), IssueExpr(IssueExpr) {}
|
|
|
|
const AccessPath &getAccessPath() const { return Path; }
|
|
const Expr *getIssueExpr() const { return IssueExpr; }
|
|
|
|
void dump(llvm::raw_ostream &OS) const override;
|
|
|
|
static bool classof(const Loan *L) { return L->getKind() == Kind::Path; }
|
|
};
|
|
|
|
/// A placeholder loan held by a function parameter, representing a borrow from
|
|
/// the caller's scope.
|
|
///
|
|
/// Created at function entry for each pointer or reference parameter with an
|
|
/// origin. Unlike PathLoan, placeholder loans:
|
|
/// - Have no IssueExpr (created at function entry, not at a borrow site)
|
|
/// - Have no AccessPath (the borrowed object is not visible to the function)
|
|
/// - Do not currently expire, but may in the future when modeling function
|
|
/// invalidations (e.g., vector::push_back)
|
|
///
|
|
/// When a placeholder loan escapes the function (e.g., via return), it
|
|
/// indicates the parameter should be marked [[clang::lifetimebound]], enabling
|
|
/// lifetime annotation suggestions.
|
|
class PlaceholderLoan : public Loan {
|
|
/// The function parameter that holds this placeholder loan.
|
|
const ParmVarDecl *PVD;
|
|
|
|
public:
|
|
PlaceholderLoan(LoanID ID, const ParmVarDecl *PVD)
|
|
: Loan(Kind::Placeholder, ID), PVD(PVD) {}
|
|
|
|
const ParmVarDecl *getParmVarDecl() const { return PVD; }
|
|
|
|
void dump(llvm::raw_ostream &OS) const override;
|
|
|
|
static bool classof(const Loan *L) {
|
|
return L->getKind() == Kind::Placeholder;
|
|
}
|
|
};
|
|
|
|
/// Manages the creation, storage and retrieval of loans.
|
|
class LoanManager {
|
|
public:
|
|
LoanManager() = default;
|
|
|
|
template <typename LoanType, typename... Args>
|
|
LoanType *createLoan(Args &&...args) {
|
|
static_assert(
|
|
std::is_same_v<LoanType, PathLoan> ||
|
|
std::is_same_v<LoanType, PlaceholderLoan>,
|
|
"createLoan can only be used with PathLoan or PlaceholderLoan");
|
|
void *Mem = LoanAllocator.Allocate<LoanType>();
|
|
auto *NewLoan =
|
|
new (Mem) LoanType(getNextLoanID(), std::forward<Args>(args)...);
|
|
AllLoans.push_back(NewLoan);
|
|
return NewLoan;
|
|
}
|
|
|
|
const Loan *getLoan(LoanID ID) const {
|
|
assert(ID.Value < AllLoans.size());
|
|
return AllLoans[ID.Value];
|
|
}
|
|
llvm::ArrayRef<const Loan *> getLoans() const { return AllLoans; }
|
|
|
|
private:
|
|
LoanID getNextLoanID() { return NextLoanID++; }
|
|
|
|
LoanID NextLoanID{0};
|
|
/// TODO(opt): Profile and evaluate the usefullness of small buffer
|
|
/// optimisation.
|
|
llvm::SmallVector<const Loan *> AllLoans;
|
|
llvm::BumpPtrAllocator LoanAllocator;
|
|
};
|
|
} // namespace clang::lifetimes::internal
|
|
|
|
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LOANS_H
|