saqut-compiler/llvm/include/clang/Analysis/Analyses/LifetimeSafety/Loans.h

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