[clang] [LifetimeSafety] Add suggestion and inference for implicit this (PR #176703)
Kashika Akhouri via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 23 10:28:28 PST 2026
https://github.com/kashika0112 updated https://github.com/llvm/llvm-project/pull/176703
>From e49d9e1fa109dc83add2bae21e01e8a9316a87fd Mon Sep 17 00:00:00 2001
From: Kashika Akhouri <akhourik at google.com>
Date: Mon, 19 Jan 2026 08:03:57 +0000
Subject: [PATCH 1/9] Add suggestion and inference for implicit this
---
.../Analysis/Analyses/LifetimeSafety/Facts.h | 2 +-
.../Analyses/LifetimeSafety/LifetimeSafety.h | 4 +
.../Analysis/Analyses/LifetimeSafety/Loans.h | 30 ++++--
.../Analyses/LifetimeSafety/Origins.h | 14 ++-
.../clang/Basic/DiagnosticSemaKinds.td | 12 +++
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 93 ++++++++++++-------
.../LifetimeSafety/FactsGenerator.cpp | 10 +-
.../LifetimeSafety/LifetimeAnnotations.cpp | 2 +
clang/lib/Analysis/LifetimeSafety/Origins.cpp | 13 +++
clang/lib/Sema/AnalysisBasedWarnings.cpp | 24 +++++
.../Sema/warn-lifetime-safety-suggestions.cpp | 15 ++-
11 files changed, 169 insertions(+), 50 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
index a66925b7302ca..1bb34e6986857 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
@@ -195,7 +195,7 @@ class TestPointFact : public Fact {
class FactManager {
public:
FactManager(const AnalysisDeclContext &AC, const CFG &Cfg)
- : OriginMgr(AC.getASTContext()) {
+ : OriginMgr(AC.getASTContext(), AC.getDecl()) {
BlockToFacts.resize(Cfg.getNumBlockIDs());
}
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 9c91355355233..2199ae023fb26 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -60,6 +60,10 @@ class LifetimeSafetyReporter {
virtual void suggestAnnotation(SuggestionScope Scope,
const ParmVarDecl *ParmToAnnotate,
const Expr *EscapeExpr) {}
+
+ // Suggests lifetime bound annotations for implicit this
+ virtual void suggestAnnotation(SuggestionScope Scope, const CXXMethodDecl *MD,
+ const Expr *EscapeExpr) {}
};
/// The main entry point for the analysis.
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Loans.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Loans.h
index ee1634a6f5ea2..a366e3e811cbf 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Loans.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Loans.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LOANS_H
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Analysis/Analyses/LifetimeSafety/Utils.h"
#include "llvm/Support/raw_ostream.h"
@@ -100,10 +101,11 @@ class PathLoan : public Loan {
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.
+/// A placeholder loan held by a function parameter or an implicit 'this'
+/// object, representing a borrow from the caller's scope.
///
-/// Created at function entry for each pointer or reference parameter with an
+/// Created at function entry for each pointer or reference parameter or for
+/// the implicit 'this' parameter of instance methods, 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)
@@ -111,17 +113,27 @@ class PathLoan : public Loan {
/// 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.
+/// indicates the parameter or method should be marked [[clang::lifetimebound]],
+/// enabling lifetime annotation suggestions.
class PlaceholderLoan : public Loan {
- /// The function parameter that holds this placeholder loan.
- const ParmVarDecl *PVD;
+ /// The function parameter or method (representing 'this') that holds this
+ /// placeholder loan.
+ llvm::PointerUnion<const ParmVarDecl *, const CXXMethodDecl *> ParamOrMethod;
public:
PlaceholderLoan(LoanID ID, const ParmVarDecl *PVD)
- : Loan(Kind::Placeholder, ID), PVD(PVD) {}
+ : Loan(Kind::Placeholder, ID), ParamOrMethod(PVD) {}
- const ParmVarDecl *getParmVarDecl() const { return PVD; }
+ PlaceholderLoan(LoanID ID, const CXXMethodDecl *MD)
+ : Loan(Kind::Placeholder, ID), ParamOrMethod(MD) {}
+
+ const ParmVarDecl *getParmVarDecl() const {
+ return ParamOrMethod.dyn_cast<const ParmVarDecl *>();
+ }
+
+ const CXXMethodDecl *getMethodDecl() const {
+ return ParamOrMethod.dyn_cast<const CXXMethodDecl *>();
+ }
void dump(llvm::raw_ostream &OS) const override;
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
index 690faae996f0e..60b607c77da4e 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_ORIGINS_H
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/TypeBase.h"
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
@@ -124,7 +125,8 @@ bool doesDeclHaveStorage(const ValueDecl *D);
/// variables and expressions.
class OriginManager {
public:
- explicit OriginManager(ASTContext &AST) : AST(AST) {}
+ explicit OriginManager(ASTContext &AST, const Decl *D)
+ : AST(AST), CurrentDecl(D) {}
/// Gets or creates the OriginList for a given ValueDecl.
///
@@ -144,6 +146,15 @@ class OriginManager {
/// \returns The OriginList, or nullptr for non-pointer rvalues.
OriginList *getOrCreateList(const Expr *E);
+ /// Gets or creates the OriginList for the implicit 'this' parameter of a
+ /// given CXXMethodDecl.
+ ///
+ /// Creates a list structure mirroring the levels of indirection in the
+ /// method's 'this' type (e.g., `S*` for a non-static method of class `S`).
+ ///
+ /// \returns The OriginList for the implicit object parameter.
+ OriginList *getOrCreateList(const CXXMethodDecl *MD);
+
const Origin &getOrigin(OriginID ID) const;
llvm::ArrayRef<Origin> getOrigins() const { return AllOrigins; }
@@ -172,6 +183,7 @@ class OriginManager {
llvm::BumpPtrAllocator ListAllocator;
llvm::DenseMap<const clang::ValueDecl *, OriginList *> DeclToList;
llvm::DenseMap<const clang::Expr *, OriginList *> ExprToList;
+ const Decl *CurrentDecl;
};
} // namespace clang::lifetimes::internal
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1ab3f537d36a3..c624a719e2583 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10832,6 +10832,18 @@ def warn_lifetime_safety_cross_tu_suggestion
InGroup<LifetimeSafetyCrossTUSuggestions>,
DefaultIgnore;
+def warn_lifetime_safety_this_intra_tu_suggestion
+ : Warning<"implict this in intra-TU function should be marked "
+ "[[clang::lifetimebound]]">,
+ InGroup<LifetimeSafetyIntraTUSuggestions>,
+ DefaultIgnore;
+
+def warn_lifetime_safety_this_cross_tu_suggestion
+ : Warning<"implicit this in cross-TU function should be marked "
+ "[[clang::lifetimebound]]">,
+ InGroup<LifetimeSafetyCrossTUSuggestions>,
+ DefaultIgnore;
+
def note_lifetime_safety_suggestion_returned_here : Note<"param returned here">;
// For non-floating point, expressions of the form x == x or x != x
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index f7383126fac38..ffdaad5026b3d 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -49,10 +49,13 @@ struct PendingWarning {
Confidence ConfidenceLevel;
};
+using AnnotationTarget =
+ llvm::PointerUnion<const ParmVarDecl *, const CXXMethodDecl *>;
+
class LifetimeChecker {
private:
llvm::DenseMap<LoanID, PendingWarning> FinalWarningsMap;
- llvm::DenseMap<const ParmVarDecl *, const Expr *> AnnotationWarningsMap;
+ llvm::DenseMap<AnnotationTarget, const Expr *> AnnotationWarningsMap;
const LoanPropagationAnalysis &LoanPropagation;
const LiveOriginsAnalysis &LiveOrigins;
const FactManager &FactMgr;
@@ -88,10 +91,14 @@ class LifetimeChecker {
for (LoanID LID : EscapedLoans) {
const Loan *L = FactMgr.getLoanMgr().getLoan(LID);
if (const auto *PL = dyn_cast<PlaceholderLoan>(L)) {
- const ParmVarDecl *PVD = PL->getParmVarDecl();
- if (PVD->hasAttr<LifetimeBoundAttr>())
- continue;
- AnnotationWarningsMap.try_emplace(PVD, OEF->getEscapeExpr());
+ if (const auto *PVD = PL->getParmVarDecl()) {
+ if (PVD->hasAttr<LifetimeBoundAttr>())
+ continue;
+ AnnotationWarningsMap.try_emplace(PVD, OEF->getEscapeExpr());
+ } else if (const auto *MD = PL->getMethodDecl()) {
+ if (!implicitObjectParamIsLifetimeBound(MD))
+ AnnotationWarningsMap.try_emplace(MD, OEF->getEscapeExpr());
+ }
}
}
}
@@ -164,50 +171,70 @@ class LifetimeChecker {
/// Returns the declaration of a function that is visible across translation
/// units, if such a declaration exists and is different from the definition.
- static const FunctionDecl *getCrossTUDecl(const ParmVarDecl &PVD,
+ static const FunctionDecl *getCrossTUDecl(const FunctionDecl &FD,
SourceManager &SM) {
- const auto *FD = dyn_cast<FunctionDecl>(PVD.getDeclContext());
- if (!FD)
- return nullptr;
- if (!FD->isExternallyVisible())
+ if (!FD.isExternallyVisible())
return nullptr;
- const FileID DefinitionFile = SM.getFileID(FD->getLocation());
- for (const FunctionDecl *Redecl : FD->redecls())
+ const FileID DefinitionFile = SM.getFileID(FD.getLocation());
+ for (const FunctionDecl *Redecl : FD.redecls())
if (SM.getFileID(Redecl->getLocation()) != DefinitionFile)
return Redecl;
return nullptr;
}
+ static const FunctionDecl *getCrossTUDecl(const ParmVarDecl &PVD,
+ SourceManager &SM) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(PVD.getDeclContext()))
+ return getCrossTUDecl(*FD, SM);
+ return nullptr;
+ }
+
void suggestAnnotations() {
if (!Reporter)
return;
SourceManager &SM = AST.getSourceManager();
- for (const auto &[PVD, EscapeExpr] : AnnotationWarningsMap) {
- if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*PVD, SM))
- Reporter->suggestAnnotation(
- SuggestionScope::CrossTU,
- CrossTUDecl->getParamDecl(PVD->getFunctionScopeIndex()),
- EscapeExpr);
- else
- Reporter->suggestAnnotation(SuggestionScope::IntraTU, PVD, EscapeExpr);
+ for (const auto &[Target, EscapeExpr] : AnnotationWarningsMap) {
+ if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>()) {
+ if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*PVD, SM))
+ Reporter->suggestAnnotation(
+ SuggestionScope::CrossTU,
+ CrossTUDecl->getParamDecl(PVD->getFunctionScopeIndex()),
+ EscapeExpr);
+ else
+ Reporter->suggestAnnotation(SuggestionScope::IntraTU, PVD,
+ EscapeExpr);
+ } else if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>()) {
+ if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*MD, SM))
+ Reporter->suggestAnnotation(SuggestionScope::CrossTU,
+ cast<const CXXMethodDecl>(CrossTUDecl),
+ EscapeExpr);
+ else
+ Reporter->suggestAnnotation(SuggestionScope::IntraTU, MD, EscapeExpr);
+ }
}
}
void inferAnnotations() {
- for (const auto &[ConstPVD, EscapeExpr] : AnnotationWarningsMap) {
- ParmVarDecl *PVD = const_cast<ParmVarDecl *>(ConstPVD);
- const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext());
- if (!FD)
- continue;
- // Propagates inferred attributes via the most recent declaration to
- // ensure visibility for callers in post-order analysis.
- FD = getDeclWithMergedLifetimeBoundAttrs(FD);
- ParmVarDecl *InferredPVD = const_cast<ParmVarDecl *>(
- FD->getParamDecl(PVD->getFunctionScopeIndex()));
- if (!InferredPVD->hasAttr<LifetimeBoundAttr>())
- InferredPVD->addAttr(
- LifetimeBoundAttr::CreateImplicit(AST, PVD->getLocation()));
+ for (const auto &[Target, EscapeExpr] : AnnotationWarningsMap) {
+ if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>()) {
+ CXXMethodDecl *MutableMD = const_cast<CXXMethodDecl *>(MD);
+ if (!MutableMD->hasAttr<LifetimeBoundAttr>())
+ MutableMD->addAttr(
+ LifetimeBoundAttr::CreateImplicit(AST, MutableMD->getLocation()));
+ } else if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>()) {
+ const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext());
+ if (!FD)
+ continue;
+ // Propagates inferred attributes via the most recent declaration to
+ // ensure visibility for callers in post-order analysis.
+ FD = getDeclWithMergedLifetimeBoundAttrs(FD);
+ ParmVarDecl *InferredPVD = const_cast<ParmVarDecl *>(
+ FD->getParamDecl(PVD->getFunctionScopeIndex()));
+ if (!InferredPVD->hasAttr<LifetimeBoundAttr>())
+ InferredPVD->addAttr(
+ LifetimeBoundAttr::CreateImplicit(AST, PVD->getLocation()));
+ }
}
}
};
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 54e19b58bd7d5..7093f0a0e005f 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -610,10 +610,18 @@ void FactsGenerator::markUseAsWrite(const DeclRefExpr *DRE) {
// parameter at the function's entry.
llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
const auto *FD = dyn_cast<FunctionDecl>(AC.getDecl());
- if (!FD)
+ if (!FD || FD->isImplicit())
return {};
llvm::SmallVector<Fact *> PlaceholderLoanFacts;
+ const Decl *D = AC.getDecl();
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(D); MD && MD->isInstance()) {
+ OriginList *List = FactMgr.getOriginMgr().getOrCreateList(MD);
+ const PlaceholderLoan *L =
+ FactMgr.getLoanMgr().createLoan<PlaceholderLoan>(MD);
+ PlaceholderLoanFacts.push_back(
+ FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
+ }
for (const ParmVarDecl *PVD : FD->parameters()) {
OriginList *List = getOriginsList(*PVD);
if (!List)
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
index 2772fe20de19b..284163ebc4bc3 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
@@ -54,6 +54,8 @@ bool isAssignmentOperatorLifetimeBound(const CXXMethodDecl *CMD) {
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
FD = getDeclWithMergedLifetimeBoundAttrs(FD);
+ if (FD->hasAttr<LifetimeBoundAttr>())
+ return true;
const TypeSourceInfo *TSI = FD->getTypeSourceInfo();
if (!TSI)
return false;
diff --git a/clang/lib/Analysis/LifetimeSafety/Origins.cpp b/clang/lib/Analysis/LifetimeSafety/Origins.cpp
index ca933f612eb08..8349d18267b62 100644
--- a/clang/lib/Analysis/LifetimeSafety/Origins.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Origins.cpp
@@ -137,6 +137,12 @@ OriginList *OriginManager::getOrCreateList(const Expr *E) {
return It->second;
QualType Type = E->getType();
+ // Special handling for 'this' expressions to share origins with the method's
+ // implicit object parameter.
+ if (isa<CXXThisExpr>(E)) {
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(CurrentDecl))
+ return getOrCreateList(MD);
+ }
// Special handling for DeclRefExpr to share origins with the underlying decl.
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
@@ -169,6 +175,13 @@ OriginList *OriginManager::getOrCreateList(const Expr *E) {
return ExprToList[E] = buildListForType(Type, E);
}
+OriginList *OriginManager::getOrCreateList(const CXXMethodDecl *MD) {
+ auto It = DeclToList.find(MD);
+ if (It != DeclToList.end())
+ return It->second;
+ return DeclToList[MD] = buildListForType(MD->getThisType(), MD);
+}
+
void OriginManager::dump(OriginID OID, llvm::raw_ostream &OS) const {
OS << OID << " (";
Origin O = getOrigin(OID);
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index d297d9e80cf2f..e79a38dd786f4 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2919,6 +2919,30 @@ class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {
<< EscapeExpr->getSourceRange();
}
+ void suggestAnnotation(SuggestionScope Scope, const CXXMethodDecl *MD,
+ const Expr *EscapeExpr) override {
+ unsigned DiagID = (Scope == SuggestionScope::CrossTU)
+ ? diag::warn_lifetime_safety_this_cross_tu_suggestion
+ : diag::warn_lifetime_safety_this_intra_tu_suggestion;
+
+ SourceLocation InsertionPoint;
+ if (auto *TSI = MD->getTypeSourceInfo())
+ InsertionPoint =
+ Lexer::getLocForEndOfToken(TSI->getTypeLoc().getEndLoc(), 0,
+ S.getSourceManager(), S.getLangOpts());
+ else
+ InsertionPoint = MD->getLocation();
+
+ S.Diag(InsertionPoint, DiagID)
+ << MD->getNameInfo().getSourceRange()
+ << FixItHint::CreateInsertion(InsertionPoint,
+ " [[clang::lifetimebound]]");
+
+ S.Diag(EscapeExpr->getBeginLoc(),
+ diag::note_lifetime_safety_suggestion_returned_here)
+ << EscapeExpr->getSourceRange();
+ }
+
private:
Sema &S;
};
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 6e3a6f1fd9117..2550346903175 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -161,16 +161,21 @@ static View return_view_static(View a) { // expected-warning {{parameter in int
return a; // expected-note {{param returned here}}
}
-//===----------------------------------------------------------------------===//
-// FIXME Test Cases
-//===----------------------------------------------------------------------===//
+struct ReturnThis {
+ const ReturnThis& get() { // expected-warning {{implict this in intra-TU function should be marked [[clang::lifetimebound]]}}.
+ return *this; // expected-note {{param returned here}}
+ }
+};
struct ReturnsSelf {
- const ReturnsSelf& get() const {
- return *this;
+ const ReturnsSelf& get() const { // expected-warning {{implict this in intra-TU function should be marked [[clang::lifetimebound]]}}.
+ return *this; // expected-note {{param returned here}}
}
};
+//===----------------------------------------------------------------------===//
+// FIXME Test Cases
+//===----------------------------------------------------------------------===//
struct ViewProvider {
MyObj data;
View getView() const {
>From 90166af1bfebadf187a72bb9a748307a992dd45b Mon Sep 17 00:00:00 2001
From: Kashika Akhouri <akhourik at google.com>
Date: Thu, 22 Jan 2026 06:38:41 +0000
Subject: [PATCH 2/9] Add implicit this lifetime attribute to TSI instead of
decl
---
.../Analyses/LifetimeSafety/LifetimeSafety.h | 4 ++
.../clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 10 ++--
.../LifetimeSafety/FactsGenerator.cpp | 2 +-
clang/lib/Sema/AnalysisBasedWarnings.cpp | 32 +++++++++---
.../Sema/warn-lifetime-safety-suggestions.cpp | 50 ++++++++++++-------
6 files changed, 65 insertions(+), 35 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 2199ae023fb26..6af29e01ce74d 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -64,6 +64,10 @@ class LifetimeSafetyReporter {
// Suggests lifetime bound annotations for implicit this
virtual void suggestAnnotation(SuggestionScope Scope, const CXXMethodDecl *MD,
const Expr *EscapeExpr) {}
+
+ // Adds inferred lifetime bound attribute for implicit this to its
+ // TypeSourceInfo
+ virtual void addLifetimeBoundToImplicitThis(const CXXMethodDecl *MD) {}
};
/// The main entry point for the analysis.
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 2d401cf8a37d7..cecfd426a4d75 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10833,7 +10833,7 @@ def warn_lifetime_safety_cross_tu_suggestion
DefaultIgnore;
def warn_lifetime_safety_this_intra_tu_suggestion
- : Warning<"implict this in intra-TU function should be marked "
+ : Warning<"implicit this in intra-TU function should be marked "
"[[clang::lifetimebound]]">,
InGroup<LifetimeSafetyIntraTUSuggestions>,
DefaultIgnore;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index ffdaad5026b3d..72d9296f9aac8 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -194,7 +194,7 @@ class LifetimeChecker {
if (!Reporter)
return;
SourceManager &SM = AST.getSourceManager();
- for (const auto &[Target, EscapeExpr] : AnnotationWarningsMap) {
+ for (auto [Target, EscapeExpr] : AnnotationWarningsMap) {
if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>()) {
if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*PVD, SM))
Reporter->suggestAnnotation(
@@ -216,12 +216,10 @@ class LifetimeChecker {
}
void inferAnnotations() {
- for (const auto &[Target, EscapeExpr] : AnnotationWarningsMap) {
+ for (auto [Target, EscapeExpr] : AnnotationWarningsMap) {
if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>()) {
- CXXMethodDecl *MutableMD = const_cast<CXXMethodDecl *>(MD);
- if (!MutableMD->hasAttr<LifetimeBoundAttr>())
- MutableMD->addAttr(
- LifetimeBoundAttr::CreateImplicit(AST, MutableMD->getLocation()));
+ if (!implicitObjectParamIsLifetimeBound(MD))
+ Reporter->addLifetimeBoundToImplicitThis(cast<CXXMethodDecl>(MD));
} else if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>()) {
const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext());
if (!FD)
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 99cef7d5db0a6..233e3e6553618 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -628,7 +628,7 @@ void FactsGenerator::markUseAsWrite(const DeclRefExpr *DRE) {
// parameter at the function's entry.
llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
const auto *FD = dyn_cast<FunctionDecl>(AC.getDecl());
- if (!FD || FD->isImplicit())
+ if (!FD)
return {};
llvm::SmallVector<Fact *> PlaceholderLoanFacts;
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index acdbd298e57a6..38b0c0360db7b 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/AnalysisBasedWarnings.h"
+#include "TypeLocBuilder.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -30,6 +31,7 @@
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
#include "clang/Analysis/Analyses/CalledOnceCheck.h"
#include "clang/Analysis/Analyses/Consumed.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h"
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/ThreadSafety.h"
@@ -2934,23 +2936,37 @@ class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {
: diag::warn_lifetime_safety_this_intra_tu_suggestion;
SourceLocation InsertionPoint;
- if (auto *TSI = MD->getTypeSourceInfo())
- InsertionPoint =
- Lexer::getLocForEndOfToken(TSI->getTypeLoc().getEndLoc(), 0,
- S.getSourceManager(), S.getLangOpts());
- else
- InsertionPoint = MD->getLocation();
-
+ InsertionPoint = Lexer::getLocForEndOfToken(
+ MD->getTypeSourceInfo()->getTypeLoc().getEndLoc(), 0,
+ S.getSourceManager(), S.getLangOpts());
S.Diag(InsertionPoint, DiagID)
<< MD->getNameInfo().getSourceRange()
<< FixItHint::CreateInsertion(InsertionPoint,
" [[clang::lifetimebound]]");
-
S.Diag(EscapeExpr->getBeginLoc(),
diag::note_lifetime_safety_suggestion_returned_here)
<< EscapeExpr->getSourceRange();
}
+ void addLifetimeBoundToImplicitThis(const CXXMethodDecl *MD) override {
+ CXXMethodDecl *MutableMD = const_cast<CXXMethodDecl *>(MD);
+ ASTContext &Ctx = S.getASTContext();
+ if (lifetimes::implicitObjectParamIsLifetimeBound(MutableMD))
+ return;
+ auto *Attr =
+ LifetimeBoundAttr::CreateImplicit(Ctx, MutableMD->getLocation());
+ QualType MethodType = MutableMD->getType();
+ QualType AttributedType =
+ Ctx.getAttributedType(Attr, MethodType, MethodType);
+ TypeLocBuilder TLB;
+ if (TypeSourceInfo *TSI = MutableMD->getTypeSourceInfo())
+ TLB.pushFullCopy(TSI->getTypeLoc());
+ AttributedTypeLoc TyLoc = TLB.push<AttributedTypeLoc>(AttributedType);
+ TyLoc.setAttr(Attr);
+ MutableMD->setType(AttributedType);
+ MutableMD->setTypeSourceInfo(TLB.getTypeSourceInfo(Ctx, AttributedType));
+ }
+
private:
Sema &S;
};
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index ca62668409bf9..de49878911213 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -12,6 +12,8 @@ struct View;
struct [[gsl::Owner]] MyObj {
int id;
+ MyObj(int i) : id(i) {}
+ MyObj() {}
~MyObj() {} // Non-trivial destructor
MyObj operator+(MyObj);
@@ -161,38 +163,48 @@ static View return_view_static(View a) { // expected-warning {{parameter in int
return a; // expected-note {{param returned here}}
}
-struct ReturnThis {
- const ReturnThis& get() { // expected-warning {{implict this in intra-TU function should be marked [[clang::lifetimebound]]}}.
- return *this; // expected-note {{param returned here}}
- }
-};
-
struct ReturnsSelf {
- const ReturnsSelf& get() const { // expected-warning {{implict this in intra-TU function should be marked [[clang::lifetimebound]]}}.
+ ReturnsSelf() {}
+ ~ReturnsSelf() {}
+ const ReturnsSelf& get() const { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
return *this; // expected-note {{param returned here}}
}
};
-//===----------------------------------------------------------------------===//
-// FIXME Test Cases
-//===----------------------------------------------------------------------===//
+struct ReturnThisAnnotated {
+ const ReturnThisAnnotated& get() [[clang::lifetimebound]] { return *this; }
+};
+
struct ViewProvider {
+ ViewProvider() {}
+ ViewProvider(int d) : data(d) {}
+ ~ViewProvider() {}
MyObj data;
- View getView() const {
- return data;
+ View getView() const { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
+ return data; // expected-note {{param returned here}}
}
};
-// FIXME: Fails to generate lifetime suggestions for the implicit 'this' parameter, as this feature is not yet implemented.
-void test_get_on_temporary() {
- const ReturnsSelf& s_ref = ReturnsSelf().get();
- (void)s_ref;
+View return_view_field(const ViewProvider& v) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+ return v.data; // expected-note {{param returned here}}
+}
+
+void test_get_on_temporary_pointer() {
+ const ReturnsSelf* s_ref = &ReturnsSelf().get(); // expected-warning {{object whose reference is captured does not live long enough}}.
+ // expected-note at -1 {{destroyed here}}
+ (void)s_ref; // expected-note {{later used here}}
+}
+
+void test_get_on_temporary_ref() {
+ const ReturnsSelf& s_ref = ReturnsSelf().get(); // expected-warning {{object whose reference is captured does not live long enough}}.
+ // expected-note at -1 {{destroyed here}}
+ (void)s_ref; // expected-note {{later used here}}
}
-// FIXME: Fails to generate lifetime suggestions for the implicit 'this' parameter, as this feature is not yet implemented.
void test_getView_on_temporary() {
- View sv = ViewProvider{1}.getView();
- (void)sv;
+ View sv = ViewProvider{1}.getView(); // expected-warning {{object whose reference is captured does not live long enough}}.
+ // expected-note at -1 {{destroyed here}}
+ (void)sv; // expected-note {{later used here}}
}
//===----------------------------------------------------------------------===//
>From 841afbabb1e27ca1c52dbcadd701b8184369bf5b Mon Sep 17 00:00:00 2001
From: Kashika Akhouri <akhourik at google.com>
Date: Thu, 22 Jan 2026 06:44:01 +0000
Subject: [PATCH 3/9] Remove obsolete check
---
clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
index f76b655edda17..93c7a86d0a57c 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
@@ -75,8 +75,6 @@ bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
// Attribute merging doesn't work well with attributes on function types (like
// 'this' param). We need to check all redeclarations.
for (const FunctionDecl *Redecl : FD->redecls()) {
- if (Redecl->hasAttr<LifetimeBoundAttr>())
- return true;
const TypeSourceInfo *TSI = Redecl->getTypeSourceInfo();
if (TSI && getLifetimeBoundAttrFromFunctionType(*TSI))
return true;
>From 2a21d049bb411fba846f85bf5802a8c1d5399710 Mon Sep 17 00:00:00 2001
From: Kashika Akhouri <akhourik at google.com>
Date: Thu, 22 Jan 2026 12:52:45 +0000
Subject: [PATCH 4/9] Add cross-TU test
---
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 2 +-
clang/lib/Sema/AnalysisBasedWarnings.cpp | 2 +-
clang/test/Sema/warn-lifetime-safety-suggestions.cpp | 8 ++++++++
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 72d9296f9aac8..471dfb14ec0a7 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -207,7 +207,7 @@ class LifetimeChecker {
} else if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>()) {
if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*MD, SM))
Reporter->suggestAnnotation(SuggestionScope::CrossTU,
- cast<const CXXMethodDecl>(CrossTUDecl),
+ cast<CXXMethodDecl>(CrossTUDecl),
EscapeExpr);
else
Reporter->suggestAnnotation(SuggestionScope::IntraTU, MD, EscapeExpr);
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 38b0c0360db7b..2bd5fe1605db1 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2950,9 +2950,9 @@ class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {
void addLifetimeBoundToImplicitThis(const CXXMethodDecl *MD) override {
CXXMethodDecl *MutableMD = const_cast<CXXMethodDecl *>(MD);
- ASTContext &Ctx = S.getASTContext();
if (lifetimes::implicitObjectParamIsLifetimeBound(MutableMD))
return;
+ ASTContext &Ctx = S.getASTContext();
auto *Attr =
LifetimeBoundAttr::CreateImplicit(Ctx, MutableMD->getLocation());
QualType MethodType = MutableMD->getType();
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index de49878911213..131fc62ccf29b 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -48,6 +48,10 @@ inline View redeclared_in_header(View a) { // expected-warning {{parameter in i
return a; // expected-note {{param returned here}}
}
+struct ReturnThis {
+ const ReturnThis& get() const; // expected-warning {{implicit this in cross-TU function should be marked [[clang::lifetimebound]]}}.
+};
+
#endif // TEST_HEADER_H
//--- test_source.cpp
@@ -163,6 +167,10 @@ static View return_view_static(View a) { // expected-warning {{parameter in int
return a; // expected-note {{param returned here}}
}
+const ReturnThis& ReturnThis::get() const {
+ return *this; // expected-note {{param returned here}}
+}
+
struct ReturnsSelf {
ReturnsSelf() {}
~ReturnsSelf() {}
>From 96438953394b1ce6a5cca90bdcb308d5e51e6879 Mon Sep 17 00:00:00 2001
From: Kashika Akhouri <akhourik at google.com>
Date: Fri, 23 Jan 2026 06:57:36 +0000
Subject: [PATCH 5/9] Resolving comments and adding more tests
---
.../Analyses/LifetimeSafety/LifetimeSafety.h | 17 +++----
.../clang/Basic/DiagnosticSemaKinds.td | 8 ++--
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 47 ++++++++++++-------
.../LifetimeSafety/FactsGenerator.cpp | 3 +-
clang/lib/Sema/AnalysisBasedWarnings.cpp | 19 ++++----
.../Sema/warn-lifetime-safety-suggestions.cpp | 40 +++++++++++++++-
6 files changed, 93 insertions(+), 41 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 6af29e01ce74d..472d32249dfd6 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -56,17 +56,18 @@ class LifetimeSafetyReporter {
SourceLocation ExpiryLoc,
Confidence Confidence) {}
- // Suggests lifetime bound annotations for function paramters
- virtual void suggestAnnotation(SuggestionScope Scope,
- const ParmVarDecl *ParmToAnnotate,
- const Expr *EscapeExpr) {}
+ // Suggests lifetime bound annotations for function paramters.
+ virtual void SuggestLifetimeboundToParmVar(SuggestionScope Scope,
+ const ParmVarDecl *ParmToAnnotate,
+ const Expr *EscapeExpr) {}
- // Suggests lifetime bound annotations for implicit this
- virtual void suggestAnnotation(SuggestionScope Scope, const CXXMethodDecl *MD,
- const Expr *EscapeExpr) {}
+ // Suggests lifetime bound annotations for implicit this.
+ virtual void SuggestLifetimeboundToImplicitThis(SuggestionScope Scope,
+ const CXXMethodDecl *MD,
+ const Expr *EscapeExpr) {}
// Adds inferred lifetime bound attribute for implicit this to its
- // TypeSourceInfo
+ // TypeSourceInfo.
virtual void addLifetimeBoundToImplicitThis(const CXXMethodDecl *MD) {}
};
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index cecfd426a4d75..eb05d8537ecfb 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10820,25 +10820,25 @@ def note_lifetime_safety_used_here : Note<"later used here">;
def note_lifetime_safety_destroyed_here : Note<"destroyed here">;
def note_lifetime_safety_returned_here : Note<"returned here">;
-def warn_lifetime_safety_intra_tu_suggestion
+def warn_lifetime_safety_intra_tu_param_suggestion
: Warning<"parameter in intra-TU function should be marked "
"[[clang::lifetimebound]]">,
InGroup<LifetimeSafetyIntraTUSuggestions>,
DefaultIgnore;
-def warn_lifetime_safety_cross_tu_suggestion
+def warn_lifetime_safety_cross_tu_param_suggestion
: Warning<"parameter in cross-TU function should be marked "
"[[clang::lifetimebound]]">,
InGroup<LifetimeSafetyCrossTUSuggestions>,
DefaultIgnore;
-def warn_lifetime_safety_this_intra_tu_suggestion
+def warn_lifetime_safety_intra_tu_this_suggestion
: Warning<"implicit this in intra-TU function should be marked "
"[[clang::lifetimebound]]">,
InGroup<LifetimeSafetyIntraTUSuggestions>,
DefaultIgnore;
-def warn_lifetime_safety_this_cross_tu_suggestion
+def warn_lifetime_safety_cross_tu_this_suggestion
: Warning<"implicit this in cross-TU function should be marked "
"[[clang::lifetimebound]]">,
InGroup<LifetimeSafetyCrossTUSuggestions>,
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 471dfb14ec0a7..a0a24ce657f72 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -190,28 +190,41 @@ class LifetimeChecker {
return nullptr;
}
+ static void SuggestWithScopeForParmVar(LifetimeSafetyReporter *Reporter,
+ const ParmVarDecl *PVD,
+ SourceManager &SM,
+ const Expr *EscapeExpr) {
+ if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*PVD, SM))
+ Reporter->SuggestLifetimeboundToParmVar(
+ SuggestionScope::CrossTU,
+ CrossTUDecl->getParamDecl(PVD->getFunctionScopeIndex()), EscapeExpr);
+ else
+ Reporter->SuggestLifetimeboundToParmVar(SuggestionScope::IntraTU, PVD,
+ EscapeExpr);
+ }
+
+ static void SuggestWithScopeForImplicitThis(LifetimeSafetyReporter *Reporter,
+ const CXXMethodDecl *MD,
+ SourceManager &SM,
+ const Expr *EscapeExpr) {
+ if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*MD, SM))
+ Reporter->SuggestLifetimeboundToImplicitThis(
+ SuggestionScope::CrossTU, cast<CXXMethodDecl>(CrossTUDecl),
+ EscapeExpr);
+ else
+ Reporter->SuggestLifetimeboundToImplicitThis(SuggestionScope::IntraTU, MD,
+ EscapeExpr);
+ }
+
void suggestAnnotations() {
if (!Reporter)
return;
SourceManager &SM = AST.getSourceManager();
for (auto [Target, EscapeExpr] : AnnotationWarningsMap) {
- if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>()) {
- if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*PVD, SM))
- Reporter->suggestAnnotation(
- SuggestionScope::CrossTU,
- CrossTUDecl->getParamDecl(PVD->getFunctionScopeIndex()),
- EscapeExpr);
- else
- Reporter->suggestAnnotation(SuggestionScope::IntraTU, PVD,
- EscapeExpr);
- } else if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>()) {
- if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*MD, SM))
- Reporter->suggestAnnotation(SuggestionScope::CrossTU,
- cast<CXXMethodDecl>(CrossTUDecl),
- EscapeExpr);
- else
- Reporter->suggestAnnotation(SuggestionScope::IntraTU, MD, EscapeExpr);
- }
+ if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>())
+ SuggestWithScopeForParmVar(Reporter, PVD, SM, EscapeExpr);
+ else if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>())
+ SuggestWithScopeForImplicitThis(Reporter, MD, SM, EscapeExpr);
}
}
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 233e3e6553618..8a27a5df85376 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -632,8 +632,7 @@ llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
return {};
llvm::SmallVector<Fact *> PlaceholderLoanFacts;
- const Decl *D = AC.getDecl();
- if (const auto *MD = dyn_cast<CXXMethodDecl>(D); MD && MD->isInstance()) {
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(FD); MD && MD->isInstance()) {
OriginList *List = FactMgr.getOriginMgr().getOrCreateList(MD);
const PlaceholderLoan *L =
FactMgr.getLoanMgr().createLoan<PlaceholderLoan>(MD);
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 2bd5fe1605db1..fb89456d9855e 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2903,16 +2903,16 @@ class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {
<< EscapeExpr->getEndLoc();
}
- void suggestAnnotation(SuggestionScope Scope,
- const ParmVarDecl *ParmToAnnotate,
- const Expr *EscapeExpr) override {
+ void SuggestLifetimeboundToParmVar(SuggestionScope Scope,
+ const ParmVarDecl *ParmToAnnotate,
+ const Expr *EscapeExpr) override {
unsigned DiagID;
switch (Scope) {
case SuggestionScope::CrossTU:
- DiagID = diag::warn_lifetime_safety_cross_tu_suggestion;
+ DiagID = diag::warn_lifetime_safety_cross_tu_param_suggestion;
break;
case SuggestionScope::IntraTU:
- DiagID = diag::warn_lifetime_safety_intra_tu_suggestion;
+ DiagID = diag::warn_lifetime_safety_intra_tu_param_suggestion;
break;
}
@@ -2929,11 +2929,12 @@ class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {
<< EscapeExpr->getSourceRange();
}
- void suggestAnnotation(SuggestionScope Scope, const CXXMethodDecl *MD,
- const Expr *EscapeExpr) override {
+ void SuggestLifetimeboundToImplicitThis(SuggestionScope Scope,
+ const CXXMethodDecl *MD,
+ const Expr *EscapeExpr) override {
unsigned DiagID = (Scope == SuggestionScope::CrossTU)
- ? diag::warn_lifetime_safety_this_cross_tu_suggestion
- : diag::warn_lifetime_safety_this_intra_tu_suggestion;
+ ? diag::warn_lifetime_safety_cross_tu_this_suggestion
+ : diag::warn_lifetime_safety_intra_tu_this_suggestion;
SourceLocation InsertionPoint;
InsertionPoint = Lexer::getLocForEndOfToken(
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 131fc62ccf29b..19726c5175eb5 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -52,6 +52,11 @@ struct ReturnThis {
const ReturnThis& get() const; // expected-warning {{implicit this in cross-TU function should be marked [[clang::lifetimebound]]}}.
};
+struct ReturnThisPointer {
+ const ReturnThisPointer* get() const; // expected-warning {{implicit this in cross-TU function should be marked [[clang::lifetimebound]]}}.
+};
+
+
#endif // TEST_HEADER_H
//--- test_source.cpp
@@ -171,6 +176,10 @@ const ReturnThis& ReturnThis::get() const {
return *this; // expected-note {{param returned here}}
}
+const ReturnThisPointer* ReturnThisPointer::get() const {
+ return this; // expected-note {{param returned here}}
+}
+
struct ReturnsSelf {
ReturnsSelf() {}
~ReturnsSelf() {}
@@ -184,7 +193,6 @@ struct ReturnThisAnnotated {
};
struct ViewProvider {
- ViewProvider() {}
ViewProvider(int d) : data(d) {}
~ViewProvider() {}
MyObj data;
@@ -215,6 +223,36 @@ void test_getView_on_temporary() {
(void)sv; // expected-note {{later used here}}
}
+void test_get_on_temporary_copy() {
+ ReturnsSelf copy = ReturnsSelf().get();
+
+ (void)copy;
+}
+
+struct MemberReturn {
+ MyObj data;
+
+ MyObj& getRef() { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
+ return data; // expected-note {{param returned here}}
+ }
+
+ MyObj& getRefExplicit() { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
+ return this->data; // expected-note {{param returned here}}
+ }
+
+ MyObj& getRefDereference() { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
+ return (*this).data; // expected-note {{param returned here}}
+ }
+
+ const MyObj* getPtr() { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
+ return &data; // expected-note {{param returned here}}
+ }
+
+ const MyObj* getPtrExplicit() { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
+ return &(this->data); // expected-note {{param returned here}}
+ }
+};
+
//===----------------------------------------------------------------------===//
// Annotation Inference Test Cases
//===----------------------------------------------------------------------===//
>From c9eb252f6d2c0bd0322ece68feae604aebfc25c3 Mon Sep 17 00:00:00 2001
From: Kashika Akhouri <akhourik at google.com>
Date: Fri, 23 Jan 2026 07:03:17 +0000
Subject: [PATCH 6/9] Nit changes
---
.../Analyses/LifetimeSafety/LifetimeSafety.h | 4 ++--
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 16 ++++++++--------
clang/lib/Sema/AnalysisBasedWarnings.cpp | 4 ++--
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 472d32249dfd6..6c802ac2db556 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -57,12 +57,12 @@ class LifetimeSafetyReporter {
Confidence Confidence) {}
// Suggests lifetime bound annotations for function paramters.
- virtual void SuggestLifetimeboundToParmVar(SuggestionScope Scope,
+ virtual void suggestLifetimeboundToParmVar(SuggestionScope Scope,
const ParmVarDecl *ParmToAnnotate,
const Expr *EscapeExpr) {}
// Suggests lifetime bound annotations for implicit this.
- virtual void SuggestLifetimeboundToImplicitThis(SuggestionScope Scope,
+ virtual void suggestLifetimeboundToImplicitThis(SuggestionScope Scope,
const CXXMethodDecl *MD,
const Expr *EscapeExpr) {}
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index a0a24ce657f72..7496b261173ae 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -190,29 +190,29 @@ class LifetimeChecker {
return nullptr;
}
- static void SuggestWithScopeForParmVar(LifetimeSafetyReporter *Reporter,
+ static void suggestWithScopeForParmVar(LifetimeSafetyReporter *Reporter,
const ParmVarDecl *PVD,
SourceManager &SM,
const Expr *EscapeExpr) {
if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*PVD, SM))
- Reporter->SuggestLifetimeboundToParmVar(
+ Reporter->suggestLifetimeboundToParmVar(
SuggestionScope::CrossTU,
CrossTUDecl->getParamDecl(PVD->getFunctionScopeIndex()), EscapeExpr);
else
- Reporter->SuggestLifetimeboundToParmVar(SuggestionScope::IntraTU, PVD,
+ Reporter->suggestLifetimeboundToParmVar(SuggestionScope::IntraTU, PVD,
EscapeExpr);
}
- static void SuggestWithScopeForImplicitThis(LifetimeSafetyReporter *Reporter,
+ static void suggestWithScopeForImplicitThis(LifetimeSafetyReporter *Reporter,
const CXXMethodDecl *MD,
SourceManager &SM,
const Expr *EscapeExpr) {
if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*MD, SM))
- Reporter->SuggestLifetimeboundToImplicitThis(
+ Reporter->suggestLifetimeboundToImplicitThis(
SuggestionScope::CrossTU, cast<CXXMethodDecl>(CrossTUDecl),
EscapeExpr);
else
- Reporter->SuggestLifetimeboundToImplicitThis(SuggestionScope::IntraTU, MD,
+ Reporter->suggestLifetimeboundToImplicitThis(SuggestionScope::IntraTU, MD,
EscapeExpr);
}
@@ -222,9 +222,9 @@ class LifetimeChecker {
SourceManager &SM = AST.getSourceManager();
for (auto [Target, EscapeExpr] : AnnotationWarningsMap) {
if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>())
- SuggestWithScopeForParmVar(Reporter, PVD, SM, EscapeExpr);
+ suggestWithScopeForParmVar(Reporter, PVD, SM, EscapeExpr);
else if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>())
- SuggestWithScopeForImplicitThis(Reporter, MD, SM, EscapeExpr);
+ suggestWithScopeForImplicitThis(Reporter, MD, SM, EscapeExpr);
}
}
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index fb89456d9855e..b4c549116d05f 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2903,7 +2903,7 @@ class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {
<< EscapeExpr->getEndLoc();
}
- void SuggestLifetimeboundToParmVar(SuggestionScope Scope,
+ void suggestLifetimeboundToParmVar(SuggestionScope Scope,
const ParmVarDecl *ParmToAnnotate,
const Expr *EscapeExpr) override {
unsigned DiagID;
@@ -2929,7 +2929,7 @@ class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {
<< EscapeExpr->getSourceRange();
}
- void SuggestLifetimeboundToImplicitThis(SuggestionScope Scope,
+ void suggestLifetimeboundToImplicitThis(SuggestionScope Scope,
const CXXMethodDecl *MD,
const Expr *EscapeExpr) override {
unsigned DiagID = (Scope == SuggestionScope::CrossTU)
>From c8ce3a33a4c60c4719562845fc45eee5f64db755 Mon Sep 17 00:00:00 2001
From: Kashika Akhouri <akhourik at google.com>
Date: Fri, 23 Jan 2026 15:39:04 +0000
Subject: [PATCH 7/9] Move TSI modification to Sema
---
clang/include/clang/Sema/Sema.h | 5 ++++
clang/lib/Sema/AnalysisBasedWarnings.cpp | 30 ++++--------------------
clang/lib/Sema/SemaDecl.cpp | 18 ++++++++++++++
3 files changed, 28 insertions(+), 25 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 23eb954ce774c..57bf19cc5532f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -33,6 +33,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
#include "clang/Basic/AttrSubjectMatchRules.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/CapturedStmt.h"
@@ -1256,6 +1257,10 @@ class Sema final : public SemaBase {
bool ForceComplain = false,
bool (*IsPlausibleResult)(QualType) = nullptr);
+ // Adds inferred lifetime bound attribute for implicit this to its
+ // TypeSourceInfo.
+ void addLifetimeBoundToImplicitThis(const CXXMethodDecl *MD);
+
/// Figure out if an expression could be turned into a call.
///
/// Use this when trying to recover from an error where the programmer may
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index b4c549116d05f..b4bd035c67720 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2906,15 +2906,10 @@ class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {
void suggestLifetimeboundToParmVar(SuggestionScope Scope,
const ParmVarDecl *ParmToAnnotate,
const Expr *EscapeExpr) override {
- unsigned DiagID;
- switch (Scope) {
- case SuggestionScope::CrossTU:
- DiagID = diag::warn_lifetime_safety_cross_tu_param_suggestion;
- break;
- case SuggestionScope::IntraTU:
- DiagID = diag::warn_lifetime_safety_intra_tu_param_suggestion;
- break;
- }
+ unsigned DiagID =
+ (Scope == SuggestionScope::CrossTU)
+ ? diag::warn_lifetime_safety_cross_tu_param_suggestion
+ : diag::warn_lifetime_safety_intra_tu_param_suggestion;
SourceLocation InsertionPoint = Lexer::getLocForEndOfToken(
ParmToAnnotate->getEndLoc(), 0, S.getSourceManager(), S.getLangOpts());
@@ -2950,22 +2945,7 @@ class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {
}
void addLifetimeBoundToImplicitThis(const CXXMethodDecl *MD) override {
- CXXMethodDecl *MutableMD = const_cast<CXXMethodDecl *>(MD);
- if (lifetimes::implicitObjectParamIsLifetimeBound(MutableMD))
- return;
- ASTContext &Ctx = S.getASTContext();
- auto *Attr =
- LifetimeBoundAttr::CreateImplicit(Ctx, MutableMD->getLocation());
- QualType MethodType = MutableMD->getType();
- QualType AttributedType =
- Ctx.getAttributedType(Attr, MethodType, MethodType);
- TypeLocBuilder TLB;
- if (TypeSourceInfo *TSI = MutableMD->getTypeSourceInfo())
- TLB.pushFullCopy(TSI->getTypeLoc());
- AttributedTypeLoc TyLoc = TLB.push<AttributedTypeLoc>(AttributedType);
- TyLoc.setAttr(Attr);
- MutableMD->setType(AttributedType);
- MutableMD->setTypeSourceInfo(TLB.getTypeSourceInfo(Ctx, AttributedType));
+ S.addLifetimeBoundToImplicitThis(const_cast<CXXMethodDecl *>(MD));
}
private:
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index ae779d6830d9b..753cfce642c22 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14735,6 +14735,24 @@ StmtResult Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
: IdentLoc);
}
+void Sema::addLifetimeBoundToImplicitThis(const CXXMethodDecl *MD) {
+ CXXMethodDecl *MutableMD = const_cast<CXXMethodDecl *>(MD);
+ if (lifetimes::implicitObjectParamIsLifetimeBound(MutableMD))
+ return;
+ auto *Attr =
+ LifetimeBoundAttr::CreateImplicit(Context, MutableMD->getLocation());
+ QualType MethodType = MutableMD->getType();
+ QualType AttributedType =
+ Context.getAttributedType(attr::LifetimeBound, MethodType, MethodType);
+ TypeLocBuilder TLB;
+ if (TypeSourceInfo *TSI = MutableMD->getTypeSourceInfo())
+ TLB.pushFullCopy(TSI->getTypeLoc());
+ AttributedTypeLoc TyLoc = TLB.push<AttributedTypeLoc>(AttributedType);
+ TyLoc.setAttr(Attr);
+ MutableMD->setType(AttributedType);
+ MutableMD->setTypeSourceInfo(TLB.getTypeSourceInfo(Context, AttributedType));
+}
+
void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (var->isInvalidDecl()) return;
>From b02401bb4a130188c748b0c4c05caeb388eac091 Mon Sep 17 00:00:00 2001
From: Kashika Akhouri <akhourik at google.com>
Date: Fri, 23 Jan 2026 17:34:20 +0000
Subject: [PATCH 8/9] Rename Reporter to SemaHelper
---
.../Analyses/LifetimeSafety/Checker.h | 2 +-
.../Analyses/LifetimeSafety/LifetimeSafety.h | 22 ++++++++++++++-----
.../Analyses/LifetimeSafety/Origins.h | 16 +++++---------
clang/include/clang/Sema/Sema.h | 4 ++--
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 16 +++++++-------
.../LifetimeSafety/FactsGenerator.cpp | 2 +-
.../LifetimeSafety/LifetimeSafety.cpp | 6 ++---
clang/lib/Analysis/LifetimeSafety/Origins.cpp | 20 ++++++++---------
clang/lib/Sema/AnalysisBasedWarnings.cpp | 12 +++++-----
clang/lib/Sema/SemaDecl.cpp | 18 +++++++--------
.../Sema/warn-lifetime-safety-suggestions.cpp | 3 +--
11 files changed, 61 insertions(+), 60 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
index 03636be7d00c3..08a0b0e3d1d11 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
@@ -28,7 +28,7 @@ namespace clang::lifetimes::internal {
void runLifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
const LiveOriginsAnalysis &LiveOrigins,
const FactManager &FactMgr, AnalysisDeclContext &ADC,
- LifetimeSafetyReporter *Reporter);
+ LifetimeSafetySemaHelper *Reporter);
} // namespace clang::lifetimes::internal
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 6c802ac2db556..dac80f06a9329 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -42,10 +42,20 @@ enum class SuggestionScope {
IntraTU // For suggestions on definitions local to a Translation Unit.
};
-class LifetimeSafetyReporter {
+/// Abstract interface for operations requiring Sema access.
+///
+/// This class exists to break a circular dependency: the LifetimeSafety
+/// analysis target cannot directly depend on clangSema (which would create the
+/// cycle: clangSema -> clangAnalysis -> clangAnalysisLifetimeSafety ->
+/// clangSema).
+///
+/// Instead, this interface is implemented in AnalysisBasedWarnings.cpp (part of
+/// clangSema), allowing the analysis to report diagnostics and modify the AST
+/// through Sema without introducing a circular dependency.
+class LifetimeSafetySemaHelper {
public:
- LifetimeSafetyReporter() = default;
- virtual ~LifetimeSafetyReporter() = default;
+ LifetimeSafetySemaHelper() = default;
+ virtual ~LifetimeSafetySemaHelper() = default;
virtual void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
SourceLocation FreeLoc,
@@ -73,7 +83,7 @@ class LifetimeSafetyReporter {
/// The main entry point for the analysis.
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetyReporter *Reporter,
+ LifetimeSafetySemaHelper *Reporter,
LifetimeSafetyStats &Stats, bool CollectStats);
namespace internal {
@@ -94,7 +104,7 @@ struct LifetimeFactory {
class LifetimeSafetyAnalysis {
public:
LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetyReporter *Reporter);
+ LifetimeSafetySemaHelper *Reporter);
void run();
@@ -107,7 +117,7 @@ class LifetimeSafetyAnalysis {
private:
AnalysisDeclContext &AC;
- LifetimeSafetyReporter *Reporter;
+ LifetimeSafetySemaHelper *Reporter;
LifetimeFactory Factory;
std::unique_ptr<FactManager> FactMgr;
std::unique_ptr<LiveOriginsAnalysis> LiveOrigins;
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
index 60b607c77da4e..8c638bdcace3f 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
@@ -125,8 +125,7 @@ bool doesDeclHaveStorage(const ValueDecl *D);
/// variables and expressions.
class OriginManager {
public:
- explicit OriginManager(ASTContext &AST, const Decl *D)
- : AST(AST), CurrentDecl(D) {}
+ explicit OriginManager(ASTContext &AST, const Decl *D);
/// Gets or creates the OriginList for a given ValueDecl.
///
@@ -146,14 +145,9 @@ class OriginManager {
/// \returns The OriginList, or nullptr for non-pointer rvalues.
OriginList *getOrCreateList(const Expr *E);
- /// Gets or creates the OriginList for the implicit 'this' parameter of a
- /// given CXXMethodDecl.
- ///
- /// Creates a list structure mirroring the levels of indirection in the
- /// method's 'this' type (e.g., `S*` for a non-static method of class `S`).
- ///
- /// \returns The OriginList for the implicit object parameter.
- OriginList *getOrCreateList(const CXXMethodDecl *MD);
+ /// Returns the OriginList for the implicit 'this' parameter if the current
+ /// declaration is an instance method.
+ std::optional<OriginList *> getThisOrigins() const { return ThisOrigins; }
const Origin &getOrigin(OriginID ID) const;
@@ -183,7 +177,7 @@ class OriginManager {
llvm::BumpPtrAllocator ListAllocator;
llvm::DenseMap<const clang::ValueDecl *, OriginList *> DeclToList;
llvm::DenseMap<const clang::Expr *, OriginList *> ExprToList;
- const Decl *CurrentDecl;
+ std::optional<OriginList *> ThisOrigins;
};
} // namespace clang::lifetimes::internal
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 57bf19cc5532f..0e91fecbb13bb 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1257,9 +1257,9 @@ class Sema final : public SemaBase {
bool ForceComplain = false,
bool (*IsPlausibleResult)(QualType) = nullptr);
- // Adds inferred lifetime bound attribute for implicit this to its
+ // Adds implicit lifetime bound attribute for implicit this to its
// TypeSourceInfo.
- void addLifetimeBoundToImplicitThis(const CXXMethodDecl *MD);
+ void addLifetimeBoundToImplicitThis(CXXMethodDecl *MD);
/// Figure out if an expression could be turned into a call.
///
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 7496b261173ae..f7354f1c2e3f8 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -59,13 +59,13 @@ class LifetimeChecker {
const LoanPropagationAnalysis &LoanPropagation;
const LiveOriginsAnalysis &LiveOrigins;
const FactManager &FactMgr;
- LifetimeSafetyReporter *Reporter;
+ LifetimeSafetySemaHelper *Reporter;
ASTContext &AST;
public:
LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
const LiveOriginsAnalysis &LiveOrigins, const FactManager &FM,
- AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter)
+ AnalysisDeclContext &ADC, LifetimeSafetySemaHelper *Reporter)
: LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM),
Reporter(Reporter), AST(ADC.getASTContext()) {
for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>())
@@ -190,7 +190,7 @@ class LifetimeChecker {
return nullptr;
}
- static void suggestWithScopeForParmVar(LifetimeSafetyReporter *Reporter,
+ static void suggestWithScopeForParmVar(LifetimeSafetySemaHelper *Reporter,
const ParmVarDecl *PVD,
SourceManager &SM,
const Expr *EscapeExpr) {
@@ -203,10 +203,10 @@ class LifetimeChecker {
EscapeExpr);
}
- static void suggestWithScopeForImplicitThis(LifetimeSafetyReporter *Reporter,
- const CXXMethodDecl *MD,
- SourceManager &SM,
- const Expr *EscapeExpr) {
+ static void
+ suggestWithScopeForImplicitThis(LifetimeSafetySemaHelper *Reporter,
+ const CXXMethodDecl *MD, SourceManager &SM,
+ const Expr *EscapeExpr) {
if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*MD, SM))
Reporter->suggestLifetimeboundToImplicitThis(
SuggestionScope::CrossTU, cast<CXXMethodDecl>(CrossTUDecl),
@@ -254,7 +254,7 @@ class LifetimeChecker {
void runLifetimeChecker(const LoanPropagationAnalysis &LP,
const LiveOriginsAnalysis &LO,
const FactManager &FactMgr, AnalysisDeclContext &ADC,
- LifetimeSafetyReporter *Reporter) {
+ LifetimeSafetySemaHelper *Reporter) {
llvm::TimeTraceScope TimeProfile("LifetimeChecker");
LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter);
}
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 8a27a5df85376..7004f7d25e962 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -633,7 +633,7 @@ llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
llvm::SmallVector<Fact *> PlaceholderLoanFacts;
if (const auto *MD = dyn_cast<CXXMethodDecl>(FD); MD && MD->isInstance()) {
- OriginList *List = FactMgr.getOriginMgr().getOrCreateList(MD);
+ OriginList *List = *FactMgr.getOriginMgr().getThisOrigins();
const PlaceholderLoan *L =
FactMgr.getLoanMgr().createLoan<PlaceholderLoan>(MD);
PlaceholderLoanFacts.push_back(
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index be0d405bd3086..c78738b0d4dc1 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -48,8 +48,8 @@ static void DebugOnlyFunction(AnalysisDeclContext &AC, const CFG &Cfg,
}
#endif
-LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetyReporter *Reporter)
+LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(
+ AnalysisDeclContext &AC, LifetimeSafetySemaHelper *Reporter)
: AC(AC), Reporter(Reporter) {}
void LifetimeSafetyAnalysis::run() {
@@ -103,7 +103,7 @@ void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM,
} // namespace internal
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetyReporter *Reporter,
+ LifetimeSafetySemaHelper *Reporter,
LifetimeSafetyStats &Stats, bool CollectStats) {
internal::LifetimeSafetyAnalysis Analysis(AC, Reporter);
Analysis.run();
diff --git a/clang/lib/Analysis/LifetimeSafety/Origins.cpp b/clang/lib/Analysis/LifetimeSafety/Origins.cpp
index 8349d18267b62..1be8feda6caf3 100644
--- a/clang/lib/Analysis/LifetimeSafety/Origins.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Origins.cpp
@@ -86,6 +86,13 @@ bool doesDeclHaveStorage(const ValueDecl *D) {
return !D->getType()->isReferenceType();
}
+OriginManager::OriginManager(ASTContext &AST, const Decl *D) : AST(AST) {
+ if (const auto *MD = llvm::dyn_cast_or_null<CXXMethodDecl>(D);
+ MD && MD->isInstance()) {
+ ThisOrigins = buildListForType(MD->getThisType(), MD);
+ }
+}
+
OriginList *OriginManager::createNode(const ValueDecl *D, QualType QT) {
OriginID NewID = getNextOriginID();
AllOrigins.emplace_back(NewID, D, QT.getTypePtrOrNull());
@@ -139,9 +146,9 @@ OriginList *OriginManager::getOrCreateList(const Expr *E) {
QualType Type = E->getType();
// Special handling for 'this' expressions to share origins with the method's
// implicit object parameter.
- if (isa<CXXThisExpr>(E)) {
- if (const auto *MD = dyn_cast<CXXMethodDecl>(CurrentDecl))
- return getOrCreateList(MD);
+ if (llvm::isa<CXXThisExpr>(E)) {
+ assert(ThisOrigins && "origins for 'this' should be set for a method decl");
+ return *ThisOrigins;
}
// Special handling for DeclRefExpr to share origins with the underlying decl.
@@ -175,13 +182,6 @@ OriginList *OriginManager::getOrCreateList(const Expr *E) {
return ExprToList[E] = buildListForType(Type, E);
}
-OriginList *OriginManager::getOrCreateList(const CXXMethodDecl *MD) {
- auto It = DeclToList.find(MD);
- if (It != DeclToList.end())
- return It->second;
- return DeclToList[MD] = buildListForType(MD->getThisType(), MD);
-}
-
void OriginManager::dump(OriginID OID, llvm::raw_ostream &OS) const {
OS << OID << " (";
Origin O = getOrigin(OID);
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index b4bd035c67720..954300df42319 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2874,10 +2874,10 @@ class CallableVisitor : public DynamicRecursiveASTVisitor {
namespace clang::lifetimes {
namespace {
-class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {
+class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
public:
- LifetimeSafetyReporterImpl(Sema &S) : S(S) {}
+ LifetimeSafetySemaHelperImpl(Sema &S) : S(S) {}
void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
SourceLocation FreeLoc, Confidence C) override {
@@ -2960,7 +2960,7 @@ LifetimeSafetyTUAnalysis(Sema &S, TranslationUnitDecl *TU,
llvm::TimeTraceScope TimeProfile("LifetimeSafetyTUAnalysis");
CallGraph CG;
CG.addToCallGraph(TU);
- lifetimes::LifetimeSafetyReporterImpl Reporter(S);
+ lifetimes::LifetimeSafetySemaHelperImpl Reporter(S);
for (auto *Node : llvm::post_order(&CG)) {
const clang::FunctionDecl *CanonicalFD =
dyn_cast_or_null<clang::FunctionDecl>(Node->getDecl());
@@ -3201,9 +3201,9 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
// stable.
if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {
if (AC.getCFG()) {
- lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);
- lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter, LSStats,
- S.CollectStats);
+ lifetimes::LifetimeSafetySemaHelperImpl LifetimeSafetySemaHelper(S);
+ lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetySemaHelper,
+ LSStats, S.CollectStats);
}
}
// Check for violations of "called once" parameter properties.
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 753cfce642c22..2bc65abf02829 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14735,22 +14735,20 @@ StmtResult Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
: IdentLoc);
}
-void Sema::addLifetimeBoundToImplicitThis(const CXXMethodDecl *MD) {
- CXXMethodDecl *MutableMD = const_cast<CXXMethodDecl *>(MD);
- if (lifetimes::implicitObjectParamIsLifetimeBound(MutableMD))
+void Sema::addLifetimeBoundToImplicitThis(CXXMethodDecl *MD) {
+ if (!MD || lifetimes::implicitObjectParamIsLifetimeBound(MD))
return;
- auto *Attr =
- LifetimeBoundAttr::CreateImplicit(Context, MutableMD->getLocation());
- QualType MethodType = MutableMD->getType();
+ auto *Attr = LifetimeBoundAttr::CreateImplicit(Context, MD->getLocation());
+ QualType MethodType = MD->getType();
QualType AttributedType =
- Context.getAttributedType(attr::LifetimeBound, MethodType, MethodType);
+ Context.getAttributedType(Attr, MethodType, MethodType);
TypeLocBuilder TLB;
- if (TypeSourceInfo *TSI = MutableMD->getTypeSourceInfo())
+ if (TypeSourceInfo *TSI = MD->getTypeSourceInfo())
TLB.pushFullCopy(TSI->getTypeLoc());
AttributedTypeLoc TyLoc = TLB.push<AttributedTypeLoc>(AttributedType);
TyLoc.setAttr(Attr);
- MutableMD->setType(AttributedType);
- MutableMD->setTypeSourceInfo(TLB.getTypeSourceInfo(Context, AttributedType));
+ MD->setType(AttributedType);
+ MD->setTypeSourceInfo(TLB.getTypeSourceInfo(Context, AttributedType));
}
void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 19726c5175eb5..319391dffe5c0 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -224,8 +224,7 @@ void test_getView_on_temporary() {
}
void test_get_on_temporary_copy() {
- ReturnsSelf copy = ReturnsSelf().get();
-
+ ReturnsSelf copy = ReturnsSelf().get();
(void)copy;
}
>From b427c0bca7c9524212dbc6ab2cf1259de8e943f2 Mon Sep 17 00:00:00 2001
From: Kashika Akhouri <akhourik at google.com>
Date: Fri, 23 Jan 2026 18:27:47 +0000
Subject: [PATCH 9/9] Rename Reporter variable to SemaHelper
---
.../Analyses/LifetimeSafety/Checker.h | 2 +-
.../Analyses/LifetimeSafety/LifetimeSafety.h | 6 +--
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 45 ++++++++++---------
.../LifetimeSafety/LifetimeSafety.cpp | 10 ++---
clang/lib/Analysis/LifetimeSafety/Origins.cpp | 3 +-
clang/lib/Sema/AnalysisBasedWarnings.cpp | 8 +---
6 files changed, 35 insertions(+), 39 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
index 08a0b0e3d1d11..5c631c92c0167 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
@@ -28,7 +28,7 @@ namespace clang::lifetimes::internal {
void runLifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
const LiveOriginsAnalysis &LiveOrigins,
const FactManager &FactMgr, AnalysisDeclContext &ADC,
- LifetimeSafetySemaHelper *Reporter);
+ LifetimeSafetySemaHelper *SemaHelper);
} // namespace clang::lifetimes::internal
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index dac80f06a9329..25d97b4af1ed5 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -83,7 +83,7 @@ class LifetimeSafetySemaHelper {
/// The main entry point for the analysis.
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetySemaHelper *Reporter,
+ LifetimeSafetySemaHelper *SemaHelper,
LifetimeSafetyStats &Stats, bool CollectStats);
namespace internal {
@@ -104,7 +104,7 @@ struct LifetimeFactory {
class LifetimeSafetyAnalysis {
public:
LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetySemaHelper *Reporter);
+ LifetimeSafetySemaHelper *SemaHelper);
void run();
@@ -117,7 +117,7 @@ class LifetimeSafetyAnalysis {
private:
AnalysisDeclContext &AC;
- LifetimeSafetySemaHelper *Reporter;
+ LifetimeSafetySemaHelper *SemaHelper;
LifetimeFactory Factory;
std::unique_ptr<FactManager> FactMgr;
std::unique_ptr<LiveOriginsAnalysis> LiveOrigins;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index f7354f1c2e3f8..91fbcc0a98650 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -59,15 +59,16 @@ class LifetimeChecker {
const LoanPropagationAnalysis &LoanPropagation;
const LiveOriginsAnalysis &LiveOrigins;
const FactManager &FactMgr;
- LifetimeSafetySemaHelper *Reporter;
+ LifetimeSafetySemaHelper *SemaHelper;
ASTContext &AST;
public:
LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
const LiveOriginsAnalysis &LiveOrigins, const FactManager &FM,
- AnalysisDeclContext &ADC, LifetimeSafetySemaHelper *Reporter)
+ AnalysisDeclContext &ADC,
+ LifetimeSafetySemaHelper *SemaHelper)
: LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM),
- Reporter(Reporter), AST(ADC.getASTContext()) {
+ SemaHelper(SemaHelper), AST(ADC.getASTContext()) {
for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>())
for (const Fact *F : FactMgr.getFacts(B))
if (const auto *EF = F->getAs<ExpireFact>())
@@ -146,7 +147,7 @@ class LifetimeChecker {
}
void issuePendingWarnings() {
- if (!Reporter)
+ if (!SemaHelper)
return;
for (const auto &[LID, Warning] : FinalWarningsMap) {
const Loan *L = FactMgr.getLoanMgr().getLoan(LID);
@@ -158,12 +159,12 @@ class LifetimeChecker {
SourceLocation ExpiryLoc = Warning.ExpiryLoc;
if (const auto *UF = CausingFact.dyn_cast<const UseFact *>())
- Reporter->reportUseAfterFree(IssueExpr, UF->getUseExpr(), ExpiryLoc,
- Confidence);
+ SemaHelper->reportUseAfterFree(IssueExpr, UF->getUseExpr(), ExpiryLoc,
+ Confidence);
else if (const auto *OEF =
CausingFact.dyn_cast<const OriginEscapesFact *>())
- Reporter->reportUseAfterReturn(IssueExpr, OEF->getEscapeExpr(),
- ExpiryLoc, Confidence);
+ SemaHelper->reportUseAfterReturn(IssueExpr, OEF->getEscapeExpr(),
+ ExpiryLoc, Confidence);
else
llvm_unreachable("Unhandled CausingFact type");
}
@@ -190,41 +191,41 @@ class LifetimeChecker {
return nullptr;
}
- static void suggestWithScopeForParmVar(LifetimeSafetySemaHelper *Reporter,
+ static void suggestWithScopeForParmVar(LifetimeSafetySemaHelper *SemaHelper,
const ParmVarDecl *PVD,
SourceManager &SM,
const Expr *EscapeExpr) {
if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*PVD, SM))
- Reporter->suggestLifetimeboundToParmVar(
+ SemaHelper->suggestLifetimeboundToParmVar(
SuggestionScope::CrossTU,
CrossTUDecl->getParamDecl(PVD->getFunctionScopeIndex()), EscapeExpr);
else
- Reporter->suggestLifetimeboundToParmVar(SuggestionScope::IntraTU, PVD,
- EscapeExpr);
+ SemaHelper->suggestLifetimeboundToParmVar(SuggestionScope::IntraTU, PVD,
+ EscapeExpr);
}
static void
- suggestWithScopeForImplicitThis(LifetimeSafetySemaHelper *Reporter,
+ suggestWithScopeForImplicitThis(LifetimeSafetySemaHelper *SemaHelper,
const CXXMethodDecl *MD, SourceManager &SM,
const Expr *EscapeExpr) {
if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*MD, SM))
- Reporter->suggestLifetimeboundToImplicitThis(
+ SemaHelper->suggestLifetimeboundToImplicitThis(
SuggestionScope::CrossTU, cast<CXXMethodDecl>(CrossTUDecl),
EscapeExpr);
else
- Reporter->suggestLifetimeboundToImplicitThis(SuggestionScope::IntraTU, MD,
- EscapeExpr);
+ SemaHelper->suggestLifetimeboundToImplicitThis(SuggestionScope::IntraTU,
+ MD, EscapeExpr);
}
void suggestAnnotations() {
- if (!Reporter)
+ if (!SemaHelper)
return;
SourceManager &SM = AST.getSourceManager();
for (auto [Target, EscapeExpr] : AnnotationWarningsMap) {
if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>())
- suggestWithScopeForParmVar(Reporter, PVD, SM, EscapeExpr);
+ suggestWithScopeForParmVar(SemaHelper, PVD, SM, EscapeExpr);
else if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>())
- suggestWithScopeForImplicitThis(Reporter, MD, SM, EscapeExpr);
+ suggestWithScopeForImplicitThis(SemaHelper, MD, SM, EscapeExpr);
}
}
@@ -232,7 +233,7 @@ class LifetimeChecker {
for (auto [Target, EscapeExpr] : AnnotationWarningsMap) {
if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>()) {
if (!implicitObjectParamIsLifetimeBound(MD))
- Reporter->addLifetimeBoundToImplicitThis(cast<CXXMethodDecl>(MD));
+ SemaHelper->addLifetimeBoundToImplicitThis(cast<CXXMethodDecl>(MD));
} else if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>()) {
const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext());
if (!FD)
@@ -254,9 +255,9 @@ class LifetimeChecker {
void runLifetimeChecker(const LoanPropagationAnalysis &LP,
const LiveOriginsAnalysis &LO,
const FactManager &FactMgr, AnalysisDeclContext &ADC,
- LifetimeSafetySemaHelper *Reporter) {
+ LifetimeSafetySemaHelper *SemaHelper) {
llvm::TimeTraceScope TimeProfile("LifetimeChecker");
- LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter);
+ LifetimeChecker Checker(LP, LO, FactMgr, ADC, SemaHelper);
}
} // namespace clang::lifetimes::internal
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index c78738b0d4dc1..bf9a65254e8fa 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -49,8 +49,8 @@ static void DebugOnlyFunction(AnalysisDeclContext &AC, const CFG &Cfg,
#endif
LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(
- AnalysisDeclContext &AC, LifetimeSafetySemaHelper *Reporter)
- : AC(AC), Reporter(Reporter) {}
+ AnalysisDeclContext &AC, LifetimeSafetySemaHelper *SemaHelper)
+ : AC(AC), SemaHelper(SemaHelper) {}
void LifetimeSafetyAnalysis::run() {
llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis");
@@ -90,7 +90,7 @@ void LifetimeSafetyAnalysis::run() {
DEBUG_WITH_TYPE("LiveOrigins",
LiveOrigins->dump(llvm::dbgs(), FactMgr->getTestPoints()));
- runLifetimeChecker(*LoanPropagation, *LiveOrigins, *FactMgr, AC, Reporter);
+ runLifetimeChecker(*LoanPropagation, *LiveOrigins, *FactMgr, AC, SemaHelper);
}
void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM,
@@ -103,9 +103,9 @@ void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM,
} // namespace internal
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetySemaHelper *Reporter,
+ LifetimeSafetySemaHelper *SemaHelper,
LifetimeSafetyStats &Stats, bool CollectStats) {
- internal::LifetimeSafetyAnalysis Analysis(AC, Reporter);
+ internal::LifetimeSafetyAnalysis Analysis(AC, SemaHelper);
Analysis.run();
if (CollectStats)
collectLifetimeStats(AC, Analysis.getFactManager().getOriginMgr(), Stats);
diff --git a/clang/lib/Analysis/LifetimeSafety/Origins.cpp b/clang/lib/Analysis/LifetimeSafety/Origins.cpp
index 1be8feda6caf3..bf539303695b1 100644
--- a/clang/lib/Analysis/LifetimeSafety/Origins.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Origins.cpp
@@ -88,9 +88,8 @@ bool doesDeclHaveStorage(const ValueDecl *D) {
OriginManager::OriginManager(ASTContext &AST, const Decl *D) : AST(AST) {
if (const auto *MD = llvm::dyn_cast_or_null<CXXMethodDecl>(D);
- MD && MD->isInstance()) {
+ MD && MD->isInstance())
ThisOrigins = buildListForType(MD->getThisType(), MD);
- }
}
OriginList *OriginManager::createNode(const ValueDecl *D, QualType QT) {
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 954300df42319..a85daf471b1cf 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2910,15 +2910,12 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
(Scope == SuggestionScope::CrossTU)
? diag::warn_lifetime_safety_cross_tu_param_suggestion
: diag::warn_lifetime_safety_intra_tu_param_suggestion;
-
SourceLocation InsertionPoint = Lexer::getLocForEndOfToken(
ParmToAnnotate->getEndLoc(), 0, S.getSourceManager(), S.getLangOpts());
-
S.Diag(ParmToAnnotate->getBeginLoc(), DiagID)
<< ParmToAnnotate->getSourceRange()
<< FixItHint::CreateInsertion(InsertionPoint,
" [[clang::lifetimebound]]");
-
S.Diag(EscapeExpr->getBeginLoc(),
diag::note_lifetime_safety_suggestion_returned_here)
<< EscapeExpr->getSourceRange();
@@ -2930,7 +2927,6 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
unsigned DiagID = (Scope == SuggestionScope::CrossTU)
? diag::warn_lifetime_safety_cross_tu_this_suggestion
: diag::warn_lifetime_safety_intra_tu_this_suggestion;
-
SourceLocation InsertionPoint;
InsertionPoint = Lexer::getLocForEndOfToken(
MD->getTypeSourceInfo()->getTypeLoc().getEndLoc(), 0,
@@ -2960,7 +2956,7 @@ LifetimeSafetyTUAnalysis(Sema &S, TranslationUnitDecl *TU,
llvm::TimeTraceScope TimeProfile("LifetimeSafetyTUAnalysis");
CallGraph CG;
CG.addToCallGraph(TU);
- lifetimes::LifetimeSafetySemaHelperImpl Reporter(S);
+ lifetimes::LifetimeSafetySemaHelperImpl SemaHelper(S);
for (auto *Node : llvm::post_order(&CG)) {
const clang::FunctionDecl *CanonicalFD =
dyn_cast_or_null<clang::FunctionDecl>(Node->getDecl());
@@ -2976,7 +2972,7 @@ LifetimeSafetyTUAnalysis(Sema &S, TranslationUnitDecl *TU,
AC.getCFGBuildOptions().AddTemporaryDtors = true;
AC.getCFGBuildOptions().setAllAlwaysAdd();
if (AC.getCFG())
- runLifetimeSafetyAnalysis(AC, &Reporter, LSStats, S.CollectStats);
+ runLifetimeSafetyAnalysis(AC, &SemaHelper, LSStats, S.CollectStats);
}
}
More information about the cfe-commits
mailing list