[clang] [LifetimeSafety] Introduce AccessPath-based expiry (PR #187708)
Gábor Horváth via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 23 07:23:55 PDT 2026
================
@@ -27,136 +27,93 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, LoanID ID) {
return OS << ID.Value;
}
+/// Represents the base of a placeholder access path, which is either a
+/// function parameter or the implicit 'this' object of an instance method.
+/// Placeholder paths never expire within the function scope, as they represent
+/// storage from the caller's scope.
+class PlaceholderBase {
+ llvm::PointerUnion<const ParmVarDecl *, const CXXMethodDecl *> ParamOrMethod;
+
+public:
+ PlaceholderBase(const ParmVarDecl *PVD) : ParamOrMethod(PVD) {}
+ PlaceholderBase(const CXXMethodDecl *MD) : ParamOrMethod(MD) {}
+ const ParmVarDecl *getParmVarDecl() const {
+ return ParamOrMethod.dyn_cast<const ParmVarDecl *>();
+ }
+ const CXXMethodDecl *getMethodDecl() const {
+ return ParamOrMethod.dyn_cast<const CXXMethodDecl *>();
+ }
+};
+
/// 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.
+/// variable or a field within it: var.field.*
+///
+/// An AccessPath consists of base path which is either a ValueDecl,
+/// MaterializeTemporaryExpr, or PlaceholderBase.
+///
+/// TODO: Model access paths of other types, e.g. field, array subscript, heap
+/// and globals.
class AccessPath {
- // An access path can be:
- // - ValueDecl * , to represent the storage location corresponding to the
- // variable declared in ValueDecl.
- // - MaterializeTemporaryExpr * , to represent the storage location of the
- // temporary object materialized via this MaterializeTemporaryExpr.
+ /// The base of the access path: a variable, temporary, or placeholder.
const llvm::PointerUnion<const clang::ValueDecl *,
- const clang::MaterializeTemporaryExpr *>
- P;
+ const clang::MaterializeTemporaryExpr *,
+ const PlaceholderBase *>
+ Base;
public:
- AccessPath(const clang::ValueDecl *D) : P(D) {}
- AccessPath(const clang::MaterializeTemporaryExpr *MTE) : P(MTE) {}
-
+ AccessPath(const clang::ValueDecl *D) : Base(D) {}
+ AccessPath(const clang::MaterializeTemporaryExpr *MTE) : Base(MTE) {}
+ AccessPath(const PlaceholderBase *PB) : Base(PB) {}
+ /// Creates an extended access path by appending a path element.
+ /// Example: AccessPath(x_path, field) creates path to `x.field`.
+ AccessPath(const AccessPath &Other) : Base(Other.Base) {}
const clang::ValueDecl *getAsValueDecl() const {
- return P.dyn_cast<const clang::ValueDecl *>();
+ return Base.dyn_cast<const clang::ValueDecl *>();
}
-
const clang::MaterializeTemporaryExpr *getAsMaterializeTemporaryExpr() const {
- return P.dyn_cast<const clang::MaterializeTemporaryExpr *>();
+ return Base.dyn_cast<const clang::MaterializeTemporaryExpr *>();
}
-
- bool operator==(const AccessPath &RHS) const { return P == RHS.P; }
+ const PlaceholderBase *getAsPlaceholderBase() const {
+ return Base.dyn_cast<const PlaceholderBase *>();
+ }
+ bool operator==(const AccessPath &RHS) const { return Base == RHS.Base; }
+ bool operator!=(const AccessPath &RHS) const { return !(Base == RHS.Base); }
+ void dump(llvm::raw_ostream &OS) const;
};
-/// An abstract base class for a single "Loan" which represents lending a
-/// storage in memory.
+/// Represents lending a storage location.
+//
+/// A loan tracks the borrowing relationship created by operations like
+/// taking a pointer/reference (&x), creating a view (std::string_view sv = s),
+/// or receiving a parameter.
+///
+/// Examples:
+/// - `int* p = &x;` creates a loan to `x`
+/// - Parameter loans have no IssueExpr (created at function entry)
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 AccessPath Path;
+ /// The expression that creates the loan, e.g., &x. Null for placeholder
----------------
Xazax-hun wrote:
Should we call this the "borrow" or "issuing" expression?
https://github.com/llvm/llvm-project/pull/187708
More information about the cfe-commits
mailing list