[clang] [LifetimeSafety] Handle escape through function call (PR #186126)
Abhinav Pradeep via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 12 07:36:07 PDT 2026
https://github.com/AbhinavPradeep created https://github.com/llvm/llvm-project/pull/186126
This is a draft PR. So far:
1. Added new fact `CallEscapeFact`. This stores a pointer to the call like expresion (currently a union of `CallExpr *` and `CXXConstructExpr *` as these are the call like expressions the analysis handles).
>From 45b8ecad6e32b1e70edd5b58d701d07e54087ce0 Mon Sep 17 00:00:00 2001
From: Abhinav Pradeep <abhinav.pradeep at oracle.com>
Date: Fri, 13 Mar 2026 00:21:23 +1000
Subject: [PATCH] Added new CallEscapeFact.
---
.../Analysis/Analyses/LifetimeSafety/Facts.h | 37 +++++++++++++++++++
clang/lib/Analysis/LifetimeSafety/Facts.cpp | 7 ++++
2 files changed, 44 insertions(+)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
index 42a71fb5a50d2..11ab374a5e82c 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
@@ -15,11 +15,13 @@
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_FACTS_H
#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
#include "clang/Analysis/Analyses/LifetimeSafety/Loans.h"
#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
#include "clang/Analysis/Analyses/LifetimeSafety/Utils.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
+#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Debug.h"
@@ -153,6 +155,7 @@ class OriginEscapesFact : public Fact {
Return, /// Escapes via return statement.
Field, /// Escapes via assignment to a field.
Global, /// Escapes via assignment to global storage.
+ Call, /// Escapes as argument to a function call.
} EscKind;
static bool classof(const Fact *F) {
@@ -222,6 +225,40 @@ class GlobalEscapeFact : public OriginEscapesFact {
const OriginManager &OM) const override;
};
+/// Represents escape of an origin through a function call.
+/// Example:
+/// void f(int *i);
+/// void g(int *j[[clang::noescape]]) {f(j)};
+/// This fact enables us to catch that the noescape parameter j escapes through
+/// the call to function f
+class CallEscapeFact : public OriginEscapesFact {
+ // Currently the analysis handles the following call-like expressions:
+ // - VisitCXXOperatorCallExpr to handle CXXOperatorCallExpr, a sub-class of
+ // CallExpr.
+ // - VisitCXXMemberCallExpr to handle CXXMemberCallExpr, a sub-class of
+ // CallExpr.
+ // - VisitCXXConstructExpr and handleGSLPointerConstruction deal with
+ // CXXConstructExpr. Whilst call like, it is not a sub-class of CallExpr.
+ // Therefore, this type is taken to be the union of CallExpr * and
+ // CXXConstructExpr *:
+ using CallLikeExprPtr = llvm::PointerUnion<CallExpr *, CXXConstructExpr *>;
+ const CallLikeExprPtr Call;
+ const unsigned ArgumentIndex;
+
+public:
+ CallEscapeFact(OriginID OID, const CallLikeExprPtr Call, const unsigned Index)
+ : OriginEscapesFact(OID, EscapeKind::Call), Call(Call),
+ ArgumentIndex(Index) {}
+ static bool classof(const Fact *F) {
+ return F->getKind() == Kind::OriginEscapes &&
+ static_cast<const OriginEscapesFact *>(F)->getEscapeKind() ==
+ EscapeKind::Call;
+ }
+ const CallLikeExprPtr getCall() const { return Call; };
+ void dump(llvm::raw_ostream &OS, const LoanManager &,
+ const OriginManager &OM) const override;
+};
+
class UseFact : public Fact {
const Expr *UseExpr;
const OriginList *OList;
diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
index 4ffc8b4195949..b03b3f7ec8a0f 100644
--- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
@@ -76,6 +76,13 @@ void GlobalEscapeFact::dump(llvm::raw_ostream &OS, const LoanManager &,
OS << ", via Global)\n";
}
+void CallEscapeFact::dump(llvm::raw_ostream &OS, const LoanManager &,
+ const OriginManager &OM) const {
+ OS << "CallEscapes (";
+ OM.dump(getEscapedOriginID(), OS);
+ OS << ", via Call)\n";
+}
+
void UseFact::dump(llvm::raw_ostream &OS, const LoanManager &,
const OriginManager &OM) const {
OS << "Use (";
More information about the cfe-commits
mailing list