[clang] [LifetimeSafety] Run analysis in post-order of CallGraph for better annotation propagation (PR #174178)
Kashika Akhouri via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 8 23:06:42 PST 2026
https://github.com/kashika0112 updated https://github.com/llvm/llvm-project/pull/174178
>From f0c7f3d76972790470a867326fdbd7311c2c92f6 Mon Sep 17 00:00:00 2001
From: Kashika Akhouri <akhourik at google.com>
Date: Fri, 2 Jan 2026 05:48:33 +0000
Subject: [PATCH 1/2] Add post-order analysis using call graph
---
clang/include/clang/Basic/LangOptions.def | 2 +
clang/include/clang/Options/Options.td | 9 ++
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 19 +++--
clang/lib/Sema/AnalysisBasedWarnings.cpp | 84 ++++++++++++++++++-
.../Sema/warn-lifetime-safety-suggestions.cpp | 19 ++---
5 files changed, 116 insertions(+), 17 deletions(-)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 8cba1dbaee24e..8b1f76a0a8382 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -505,6 +505,8 @@ LANGOPT(EnableLifetimeSafety, 1, 0, NotCompatible, "Experimental lifetime safety
LANGOPT(EnableLifetimeSafetyInference, 1, 0, NotCompatible, "Experimental lifetime safety inference analysis for C++")
+LANGOPT(EnableLifetimeSafetyInferencePostOrder, 1, 0, NotCompatible, "Experimental lifetime safety inference analysis in post-order for C++")
+
LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type")
#undef LANGOPT
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 04756ce486eaf..5bc3e6a6b1e7a 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -1972,6 +1972,15 @@ defm lifetime_safety_inference
BothFlags<[], [CC1Option],
" experimental lifetime safety inference for C++">>;
+defm lifetime_safety_inference_post_order
+ : BoolFOption<"experimental-lifetime-safety-inference-post-order",
+ LangOpts<"EnableLifetimeSafetyInferencePostOrder">,
+ DefaultFalse, PosFlag<SetTrue, [], [CC1Option], "Enable">,
+ NegFlag<SetFalse, [], [CC1Option], "Disable">,
+ BothFlags<[], [CC1Option],
+ " experimental lifetime safety inference in "
+ "post-order for C++">>;
+
defm addrsig : BoolFOption<"addrsig",
CodeGenOpts<"Addrsig">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Emit">,
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index ff2650be594f5..9d93c837495e5 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -194,16 +194,23 @@ class LifetimeChecker {
}
void inferAnnotations() {
- // FIXME: To maximise inference propagation, functions should be analyzed in
- // post-order of the call graph, allowing inferred annotations to propagate
- // through the call chain
- // FIXME: Add the inferred attribute to all redeclarations of the function,
- // not just the definition being analyzed.
for (const auto &[ConstPVD, EscapeExpr] : AnnotationWarningsMap) {
ParmVarDecl *PVD = const_cast<ParmVarDecl *>(ConstPVD);
- if (!PVD->hasAttr<LifetimeBoundAttr>())
+ if (!PVD->hasAttr<LifetimeBoundAttr>()) {
PVD->addAttr(
LifetimeBoundAttr::CreateImplicit(AST, PVD->getLocation()));
+ if (const FunctionDecl *FD =
+ dyn_cast<FunctionDecl>(PVD->getDeclContext())) {
+ for (const FunctionDecl *Redecl : FD->redecls()) {
+ if (Redecl != FD)
+ if (const ParmVarDecl *RedeclPVD =
+ Redecl->getParamDecl(PVD->getFunctionScopeIndex());
+ RedeclPVD)
+ const_cast<ParmVarDecl *>(RedeclPVD)->addAttr(
+ LifetimeBoundAttr::CreateImplicit(AST, PVD->getLocation()));
+ }
+ }
+ }
}
}
};
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 7b08648080710..85d3c5fb4caff 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/Type.h"
@@ -36,6 +37,7 @@
#include "clang/Analysis/Analyses/UnsafeBufferUsage.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CallGraph.h"
#include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticSema.h"
@@ -48,6 +50,7 @@
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -2915,6 +2918,43 @@ class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {
} // namespace
} // namespace clang::lifetimes
+class CallGraphBuilder : public clang::RecursiveASTVisitor<CallGraphBuilder> {
+ clang::CallGraph &CG;
+ clang::Sema &S;
+ clang::FunctionDecl *CurrentFD = nullptr;
+
+public:
+ explicit CallGraphBuilder(clang::CallGraph &CG, clang::Sema &S)
+ : CG(CG), S(S) {}
+
+ void addCallsFrom(clang::FunctionDecl *FD) {
+ CurrentFD = FD;
+ if (FD->hasBody())
+ TraverseStmt(FD->getBody());
+ }
+
+ // Visitor for call expressions.
+ bool VisitCallExpr(clang::CallExpr *CE) {
+ if (clang::FunctionDecl *CalleeFD = CE->getDirectCallee()) {
+ const clang::FunctionDecl *Def = nullptr;
+ if (CalleeFD->hasBody(Def) && Def) {
+ if (!S.getSourceManager().isInSystemHeader(Def->getLocation())) {
+ const FunctionDecl *CanonicalCaller = CurrentFD->getCanonicalDecl();
+ const FunctionDecl *CanonicalCallee = Def->getCanonicalDecl();
+
+ clang::CallGraphNode *CallerNode = CG.getOrInsertNode(
+ const_cast<clang::FunctionDecl *>(CanonicalCaller));
+ clang::CallGraphNode *CalleeNode = CG.getOrInsertNode(
+ const_cast<clang::FunctionDecl *>(CanonicalCallee));
+ // Add an edge from caller to callee.
+ CallerNode->addCallee({CalleeNode, CE});
+ }
+ }
+ }
+ return true;
+ }
+};
+
void clang::sema::AnalysisBasedWarnings::IssueWarnings(
TranslationUnitDecl *TU) {
if (!TU)
@@ -2969,6 +3009,46 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
CallableVisitor(CallAnalyzers, TU->getOwningModule())
.TraverseTranslationUnitDecl(TU);
}
+
+ if (S.getLangOpts().EnableLifetimeSafety && S.getLangOpts().CPlusPlus &&
+ S.getLangOpts().EnableLifetimeSafetyInferencePostOrder) {
+ llvm::SmallVector<const FunctionDecl *, 64> AllFunctions;
+ auto AddFunctionToList = [&](const Decl *D) -> void {
+ if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->doesThisDeclarationHaveABody() &&
+ !S.getSourceManager().isInSystemHeader(FD->getLocation()))
+ AllFunctions.push_back(FD);
+ };
+ CallableVisitor(AddFunctionToList, TU->getOwningModule())
+ .TraverseTranslationUnitDecl(TU);
+
+ if (AllFunctions.empty())
+ return;
+
+ clang::CallGraph CG;
+ for (const clang::FunctionDecl *FD : AllFunctions)
+ CG.getOrInsertNode(const_cast<clang::FunctionDecl *>(FD));
+
+ CallGraphBuilder Builder(CG, S);
+ for (const clang::FunctionDecl *FD : AllFunctions)
+ Builder.addCallsFrom(const_cast<clang::FunctionDecl *>(FD));
+
+ lifetimes::LifetimeSafetyReporterImpl Reporter(S);
+ for (auto *Node : llvm::post_order(&CG)) {
+ if (const clang::FunctionDecl *CanonicalFD =
+ dyn_cast_or_null<clang::FunctionDecl>(Node->getDecl())) {
+ const FunctionDecl *FD = CanonicalFD->getDefinition();
+ if (!FD)
+ continue;
+
+ AnalysisDeclContext AC(nullptr, FD);
+ AC.getCFGBuildOptions().PruneTriviallyFalseEdges = false;
+ AC.getCFGBuildOptions().AddLifetime = true;
+ AC.getCFGBuildOptions().setAllAlwaysAdd();
+ runLifetimeSafetyAnalysis(AC, &Reporter, LSStats, S.CollectStats);
+ }
+ }
+ }
}
void clang::sema::AnalysisBasedWarnings::IssueWarnings(
@@ -3015,7 +3095,9 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
AC.getCFGBuildOptions().AddCXXNewAllocator = false;
AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true;
- bool EnableLifetimeSafetyAnalysis = S.getLangOpts().EnableLifetimeSafety;
+ bool EnableLifetimeSafetyAnalysis =
+ S.getLangOpts().EnableLifetimeSafety &&
+ !S.getLangOpts().EnableLifetimeSafetyInferencePostOrder;
if (EnableLifetimeSafetyAnalysis)
AC.getCFGBuildOptions().AddLifetime = true;
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 8a328dfbc8d9e..5aeb76e530bad 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
-// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -fexperimental-lifetime-safety-inference -Wexperimental-lifetime-safety-suggestions -Wexperimental-lifetime-safety -Wno-dangling -I%t -verify %t/test_source.cpp
+// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -fexperimental-lifetime-safety-inference -fexperimental-lifetime-safety-inference-post-order -Wexperimental-lifetime-safety-suggestions -Wexperimental-lifetime-safety -Wno-dangling -I%t -verify %t/test_source.cpp
View definition_before_header(View a);
@@ -204,9 +204,8 @@ MyObj* return_pointer_by_func(MyObj* a) { // expected-warning {{paramete
namespace incorrect_order_inference_view {
View return_view_callee(View a);
-// FIXME: No lifetime annotation suggestion when functions are not present in the callee-before-caller pattern
-View return_view_caller(View a) {
- return return_view_callee(a);
+View return_view_caller(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+ return return_view_callee(a); // expected-note {{param returned here}}
}
View return_view_callee(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
@@ -218,8 +217,8 @@ namespace incorrect_order_inference_object {
MyObj* return_object_callee(MyObj* a);
// FIXME: No lifetime annotation suggestion warning when functions are not present in the callee-before-caller pattern
-MyObj* return_object_caller(MyObj* a) {
- return return_object_callee(a);
+MyObj* return_object_caller(MyObj* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+ return return_object_callee(a); // expected-note {{param returned here}}
}
MyObj* return_object_callee(MyObj* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
@@ -268,14 +267,14 @@ T* template_identity(T* a) { // expected-warning {{parameter in intra
}
template<typename T>
-T* template_caller(T* a) {
- return template_identity(a); // expected-note {{in instantiation of function template specialization 'inference_with_templates::template_identity<MyObj>' requested here}}
+T* template_caller(T* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+ return template_identity(a); // expected-note {{param returned here}}
}
-// FIXME: Fails to detect UAR as template instantiations are deferred to the end of the Translation Unit.
MyObj* test_template_inference_with_stack() {
MyObj local_stack;
- return template_caller(&local_stack); // expected-note {{in instantiation of function template specialization 'inference_with_templates::template_caller<MyObj>' requested here}}
+ return template_caller(&local_stack); // expected-warning {{address of stack memory is returned later}}
+ // expected-note at -1 {{returned here}}
}
} // namespace inference_with_templates
>From 025f643d7a7c451ef505daa5f0462ceaef4ba757 Mon Sep 17 00:00:00 2001
From: Kashika Akhouri <akhourik at google.com>
Date: Wed, 7 Jan 2026 07:57:15 +0000
Subject: [PATCH 2/2] Use addToCallGraph istead of custom visitor
---
clang/include/clang/Basic/LangOptions.def | 3 +-
clang/include/clang/Options/Options.td | 13 +--
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 21 ++--
.../LifetimeSafety/FactsGenerator.cpp | 11 +-
clang/lib/Sema/AnalysisBasedWarnings.cpp | 101 +++++-------------
.../Sema/warn-lifetime-safety-suggestions.cpp | 3 +-
6 files changed, 50 insertions(+), 102 deletions(-)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 8b1f76a0a8382..36fec24638363 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -505,7 +505,8 @@ LANGOPT(EnableLifetimeSafety, 1, 0, NotCompatible, "Experimental lifetime safety
LANGOPT(EnableLifetimeSafetyInference, 1, 0, NotCompatible, "Experimental lifetime safety inference analysis for C++")
-LANGOPT(EnableLifetimeSafetyInferencePostOrder, 1, 0, NotCompatible, "Experimental lifetime safety inference analysis in post-order for C++")
+// TODO: Remove flag and default to end-of-TU analysis for lifetime safety after performance validation.
+LANGOPT(EnableLifetimeSafetyTUAnalysis, 1, 0, NotCompatible, "Experimental lifetime safety at translation-unit end, analyzing functions in call graph post-order for C++")
LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type")
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 5bc3e6a6b1e7a..f4b6d176e168a 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -1972,14 +1972,15 @@ defm lifetime_safety_inference
BothFlags<[], [CC1Option],
" experimental lifetime safety inference for C++">>;
-defm lifetime_safety_inference_post_order
- : BoolFOption<"experimental-lifetime-safety-inference-post-order",
- LangOpts<"EnableLifetimeSafetyInferencePostOrder">,
- DefaultFalse, PosFlag<SetTrue, [], [CC1Option], "Enable">,
+defm lifetime_safety_tu_analysis
+ : BoolFOption<"experimental-lifetime-safety-tu-analysis",
+ LangOpts<"EnableLifetimeSafetyTUAnalysis">, DefaultFalse,
+ PosFlag<SetTrue, [], [CC1Option], "Enable">,
NegFlag<SetFalse, [], [CC1Option], "Disable">,
BothFlags<[], [CC1Option],
- " experimental lifetime safety inference in "
- "post-order for C++">>;
+ " run lifetime safety analysis at translation-unit "
+ "end, analyzing functions in call graph post-order "
+ "to best propagate inferred annotations">>;
defm addrsig : BoolFOption<"addrsig",
CodeGenOpts<"Addrsig">, DefaultFalse,
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 9d93c837495e5..eebcfa8a90a3e 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -196,20 +196,15 @@ class LifetimeChecker {
void inferAnnotations() {
for (const auto &[ConstPVD, EscapeExpr] : AnnotationWarningsMap) {
ParmVarDecl *PVD = const_cast<ParmVarDecl *>(ConstPVD);
- if (!PVD->hasAttr<LifetimeBoundAttr>()) {
- PVD->addAttr(
+ const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext());
+ if (!FD)
+ continue;
+ const FunctionDecl *CanonicalFD = FD->getCanonicalDecl();
+ ParmVarDecl *CanonicalPVD = const_cast<ParmVarDecl *>(
+ CanonicalFD->getParamDecl(PVD->getFunctionScopeIndex()));
+ if (!CanonicalPVD->hasAttr<LifetimeBoundAttr>()) {
+ CanonicalPVD->addAttr(
LifetimeBoundAttr::CreateImplicit(AST, PVD->getLocation()));
- if (const FunctionDecl *FD =
- dyn_cast<FunctionDecl>(PVD->getDeclContext())) {
- for (const FunctionDecl *Redecl : FD->redecls()) {
- if (Redecl != FD)
- if (const ParmVarDecl *RedeclPVD =
- Redecl->getParamDecl(PVD->getFunctionScopeIndex());
- RedeclPVD)
- const_cast<ParmVarDecl *>(RedeclPVD)->addAttr(
- LifetimeBoundAttr::CreateImplicit(AST, PVD->getLocation()));
- }
- }
}
}
}
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 6a213a71afe12..b9e0816092595 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -392,11 +392,12 @@ void FactsGenerator::handleFunctionCall(const Expr *Call,
bool IsGslConstruction) {
OriginList *CallList = getOriginsList(*Call);
// Ignore functions returning values with no origin.
- if (!FD || !CallList)
+ const FunctionDecl *CanonicalFD = FD ? FD->getCanonicalDecl() : nullptr;
+ if (!CanonicalFD || !CallList)
return;
- auto IsArgLifetimeBound = [FD](unsigned I) -> bool {
+ auto IsArgLifetimeBound = [CanonicalFD](unsigned I) -> bool {
const ParmVarDecl *PVD = nullptr;
- if (const auto *Method = dyn_cast<CXXMethodDecl>(FD);
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(CanonicalFD);
Method && Method->isInstance()) {
if (I == 0)
// For the 'this' argument, the attribute is on the method itself.
@@ -405,9 +406,9 @@ void FactsGenerator::handleFunctionCall(const Expr *Call,
// For explicit arguments, find the corresponding parameter
// declaration.
PVD = Method->getParamDecl(I - 1);
- } else if (I < FD->getNumParams()) {
+ } else if (I < CanonicalFD->getNumParams()) {
// For free functions or static methods.
- PVD = FD->getParamDecl(I);
+ PVD = CanonicalFD->getParamDecl(I);
}
return PVD ? PVD->hasAttr<clang::LifetimeBoundAttr>() : false;
};
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 85d3c5fb4caff..56d7db649afbe 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -23,7 +23,6 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/ParentMap.h"
-#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/Type.h"
@@ -55,6 +54,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/TimeProfiler.h"
#include <algorithm>
#include <deque>
#include <iterator>
@@ -2918,42 +2918,29 @@ class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {
} // namespace
} // namespace clang::lifetimes
-class CallGraphBuilder : public clang::RecursiveASTVisitor<CallGraphBuilder> {
- clang::CallGraph &CG;
- clang::Sema &S;
- clang::FunctionDecl *CurrentFD = nullptr;
-
-public:
- explicit CallGraphBuilder(clang::CallGraph &CG, clang::Sema &S)
- : CG(CG), S(S) {}
-
- void addCallsFrom(clang::FunctionDecl *FD) {
- CurrentFD = FD;
- if (FD->hasBody())
- TraverseStmt(FD->getBody());
- }
-
- // Visitor for call expressions.
- bool VisitCallExpr(clang::CallExpr *CE) {
- if (clang::FunctionDecl *CalleeFD = CE->getDirectCallee()) {
- const clang::FunctionDecl *Def = nullptr;
- if (CalleeFD->hasBody(Def) && Def) {
- if (!S.getSourceManager().isInSystemHeader(Def->getLocation())) {
- const FunctionDecl *CanonicalCaller = CurrentFD->getCanonicalDecl();
- const FunctionDecl *CanonicalCallee = Def->getCanonicalDecl();
-
- clang::CallGraphNode *CallerNode = CG.getOrInsertNode(
- const_cast<clang::FunctionDecl *>(CanonicalCaller));
- clang::CallGraphNode *CalleeNode = CG.getOrInsertNode(
- const_cast<clang::FunctionDecl *>(CanonicalCallee));
- // Add an edge from caller to callee.
- CallerNode->addCallee({CalleeNode, CE});
- }
- }
- }
- return true;
+static void
+LifetimeSafetyTUAnalysis(Sema &S, TranslationUnitDecl *TU,
+ clang::lifetimes::LifetimeSafetyStats &LSStats) {
+ llvm::TimeTraceScope TimeProfile("LifetimeSafetyTUAnalysis");
+ CallGraph CG;
+ CG.addToCallGraph(TU);
+ lifetimes::LifetimeSafetyReporterImpl Reporter(S);
+ for (auto *Node : llvm::post_order(&CG)) {
+ const clang::FunctionDecl *CanonicalFD =
+ dyn_cast_or_null<clang::FunctionDecl>(Node->getDecl());
+ if (!CanonicalFD)
+ continue;
+ const FunctionDecl *FD = CanonicalFD->getDefinition();
+ if (!FD)
+ continue;
+ AnalysisDeclContext AC(nullptr, FD);
+ AC.getCFGBuildOptions().PruneTriviallyFalseEdges = false;
+ AC.getCFGBuildOptions().AddLifetime = true;
+ AC.getCFGBuildOptions().setAllAlwaysAdd();
+ if (AC.getCFG())
+ runLifetimeSafetyAnalysis(AC, &Reporter, LSStats, S.CollectStats);
}
-};
+}
void clang::sema::AnalysisBasedWarnings::IssueWarnings(
TranslationUnitDecl *TU) {
@@ -3011,44 +2998,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
}
if (S.getLangOpts().EnableLifetimeSafety && S.getLangOpts().CPlusPlus &&
- S.getLangOpts().EnableLifetimeSafetyInferencePostOrder) {
- llvm::SmallVector<const FunctionDecl *, 64> AllFunctions;
- auto AddFunctionToList = [&](const Decl *D) -> void {
- if (const auto *FD = dyn_cast<FunctionDecl>(D))
- if (FD->doesThisDeclarationHaveABody() &&
- !S.getSourceManager().isInSystemHeader(FD->getLocation()))
- AllFunctions.push_back(FD);
- };
- CallableVisitor(AddFunctionToList, TU->getOwningModule())
- .TraverseTranslationUnitDecl(TU);
-
- if (AllFunctions.empty())
- return;
-
- clang::CallGraph CG;
- for (const clang::FunctionDecl *FD : AllFunctions)
- CG.getOrInsertNode(const_cast<clang::FunctionDecl *>(FD));
-
- CallGraphBuilder Builder(CG, S);
- for (const clang::FunctionDecl *FD : AllFunctions)
- Builder.addCallsFrom(const_cast<clang::FunctionDecl *>(FD));
-
- lifetimes::LifetimeSafetyReporterImpl Reporter(S);
- for (auto *Node : llvm::post_order(&CG)) {
- if (const clang::FunctionDecl *CanonicalFD =
- dyn_cast_or_null<clang::FunctionDecl>(Node->getDecl())) {
- const FunctionDecl *FD = CanonicalFD->getDefinition();
- if (!FD)
- continue;
-
- AnalysisDeclContext AC(nullptr, FD);
- AC.getCFGBuildOptions().PruneTriviallyFalseEdges = false;
- AC.getCFGBuildOptions().AddLifetime = true;
- AC.getCFGBuildOptions().setAllAlwaysAdd();
- runLifetimeSafetyAnalysis(AC, &Reporter, LSStats, S.CollectStats);
- }
- }
- }
+ S.getLangOpts().EnableLifetimeSafetyTUAnalysis)
+ LifetimeSafetyTUAnalysis(S, TU, LSStats);
}
void clang::sema::AnalysisBasedWarnings::IssueWarnings(
@@ -3097,7 +3048,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
bool EnableLifetimeSafetyAnalysis =
S.getLangOpts().EnableLifetimeSafety &&
- !S.getLangOpts().EnableLifetimeSafetyInferencePostOrder;
+ !S.getLangOpts().EnableLifetimeSafetyTUAnalysis;
if (EnableLifetimeSafetyAnalysis)
AC.getCFGBuildOptions().AddLifetime = true;
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 5aeb76e530bad..8e66a672273d5 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
-// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -fexperimental-lifetime-safety-inference -fexperimental-lifetime-safety-inference-post-order -Wexperimental-lifetime-safety-suggestions -Wexperimental-lifetime-safety -Wno-dangling -I%t -verify %t/test_source.cpp
+// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -fexperimental-lifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wexperimental-lifetime-safety-suggestions -Wexperimental-lifetime-safety -Wno-dangling -I%t -verify %t/test_source.cpp
View definition_before_header(View a);
@@ -216,7 +216,6 @@ View return_view_callee(View a) { // expected-warning {{parameter in intra-T
namespace incorrect_order_inference_object {
MyObj* return_object_callee(MyObj* a);
-// FIXME: No lifetime annotation suggestion warning when functions are not present in the callee-before-caller pattern
MyObj* return_object_caller(MyObj* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
return return_object_callee(a); // expected-note {{param returned here}}
}
More information about the cfe-commits
mailing list