[llvm-branch-commits] [clang] [LifetimeSafety][NFC] Collect accessed fields in a unified pre-scan (PR #201511)
Zhijie Wang via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Jun 11 00:01:34 PDT 2026
https://github.com/aeft updated https://github.com/llvm/llvm-project/pull/201511
>From a7a42ac6e97bfc57f1c45e07d2e5891b5623b442 Mon Sep 17 00:00:00 2001
From: Zhijie Wang <yesterda9 at gmail.com>
Date: Wed, 3 Jun 2026 20:58:24 -0700
Subject: [PATCH] [LifetimeSafety][NFC] Collect accessed fields in a unified
pre-scan
---
.../Analyses/LifetimeSafety/Origins.h | 19 +++++++++---
clang/lib/Analysis/LifetimeSafety/Origins.cpp | 30 ++++++++++++++-----
2 files changed, 37 insertions(+), 12 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
index 816228532b31e..823ddbb6fd6ae 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
@@ -21,6 +21,7 @@
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
#include "clang/Analysis/Analyses/LifetimeSafety/Utils.h"
#include "clang/Analysis/AnalysisDeclContext.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/raw_ostream.h"
namespace clang::lifetimes::internal {
@@ -196,6 +197,10 @@ class OriginManager {
bool hasOrigins(QualType QT) const;
bool hasOrigins(const Expr *E) const;
+ bool isAccessedField(const FieldDecl *FD) const {
+ return AccessedFields.contains(FD);
+ }
+
void dump(OriginID OID, llvm::raw_ostream &OS,
const FieldDecl *FD = nullptr) const;
@@ -215,10 +220,13 @@ class OriginManager {
void initializeThisOrigins(const Decl *D);
- /// Pre-scans the function body (and constructor init lists) to discover
- /// return types of lifetime-annotated calls (currently
- /// [[clang::lifetimebound]]), registering them for origin tracking.
- void collectLifetimeAnnotatedOriginTypes(const AnalysisDeclContext &AC);
+ /// Pre-scans the function body (and constructor init lists) to discover:
+ ///
+ /// 1. Return types of lifetime-annotated calls (currently
+ /// [[clang::lifetimebound]]), registering them for origin tracking.
+ ///
+ /// 2. The fields it accesses; the rest are excluded from origin tracking.
+ void runPreScan(const AnalysisDeclContext &AC);
void registerLifetimeAnnotatedOriginType(QualType QT);
ASTContext &AST;
@@ -234,6 +242,9 @@ class OriginManager {
/// because of lifetime annotations (currently [[clang::lifetimebound]]) on
/// functions that return them.
llvm::DenseSet<const Type *> LifetimeAnnotatedOriginTypes;
+ /// Fields accessed in the function body (or constructor init lists).
+ /// Fields outside this set are excluded from origin tracking.
+ llvm::SmallPtrSet<const FieldDecl *, 8> AccessedFields;
};
} // namespace clang::lifetimes::internal
diff --git a/clang/lib/Analysis/LifetimeSafety/Origins.cpp b/clang/lib/Analysis/LifetimeSafety/Origins.cpp
index c4cd935bfcb6d..510232f5dc983 100644
--- a/clang/lib/Analysis/LifetimeSafety/Origins.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Origins.cpp
@@ -51,8 +51,7 @@ class MissingOriginCollector
LifetimeSafetyStats &LSStats;
};
-class LifetimeAnnotatedOriginTypeCollector
- : public RecursiveASTVisitor<LifetimeAnnotatedOriginTypeCollector> {
+class PreScanCollector : public RecursiveASTVisitor<PreScanCollector> {
public:
bool VisitCallExpr(const CallExpr *CE) {
// Indirect calls (e.g., function pointers) are skipped because lifetime
@@ -67,6 +66,12 @@ class LifetimeAnnotatedOriginTypeCollector
return true;
}
+ bool VisitMemberExpr(const MemberExpr *ME) {
+ if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ AccessedFields.insert(FD);
+ return true;
+ }
+
bool shouldVisitLambdaBody() const { return false; }
bool shouldVisitTemplateInstantiations() const { return true; }
@@ -74,8 +79,13 @@ class LifetimeAnnotatedOriginTypeCollector
return CollectedTypes;
}
+ const llvm::SmallPtrSet<const FieldDecl *, 8> &getAccessedFields() const {
+ return AccessedFields;
+ }
+
private:
llvm::SmallVector<QualType> CollectedTypes;
+ llvm::SmallPtrSet<const FieldDecl *, 8> AccessedFields;
void collect(const FunctionDecl *FD, QualType RetType) {
if (!FD)
@@ -159,7 +169,7 @@ bool doesDeclHaveStorage(const ValueDecl *D) {
OriginManager::OriginManager(const AnalysisDeclContext &AC)
: AST(AC.getASTContext()) {
- collectLifetimeAnnotatedOriginTypes(AC);
+ runPreScan(AC);
initializeThisOrigins(AC.getDecl());
}
@@ -315,16 +325,20 @@ void OriginManager::collectMissingOrigins(Stmt &FunctionBody,
Collector.TraverseStmt(const_cast<Stmt *>(&FunctionBody));
}
-void OriginManager::collectLifetimeAnnotatedOriginTypes(
- const AnalysisDeclContext &AC) {
- LifetimeAnnotatedOriginTypeCollector Collector;
+void OriginManager::runPreScan(const AnalysisDeclContext &AC) {
+ PreScanCollector Collector;
if (Stmt *Body = AC.getBody())
Collector.TraverseStmt(Body);
if (const auto *CD = dyn_cast<CXXConstructorDecl>(AC.getDecl()))
- for (const auto *Init : CD->inits())
- Collector.TraverseStmt(Init->getInit());
+ for (const auto *Init : CD->inits()) {
+ if (const FieldDecl *FD = Init->getAnyMember())
+ AccessedFields.insert(FD);
+ if (Expr *InitE = Init->getInit())
+ Collector.TraverseStmt(InitE);
+ }
for (QualType QT : Collector.getCollectedTypes())
registerLifetimeAnnotatedOriginType(QT);
+ AccessedFields.insert_range(Collector.getAccessedFields());
}
void OriginManager::registerLifetimeAnnotatedOriginType(QualType QT) {
More information about the llvm-branch-commits
mailing list