[clang] [analyzer] Skip LifetimeEnd nodes in getNextStmtForDiagnostics (PR #228045)
Benedek Kaibas via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 9 14:58:16 PDT 2026
https://github.com/benedekaibas updated https://github.com/llvm/llvm-project/pull/228045
>From b65cfba070d96275efb405a26fa46596f2063b90 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Thu, 1 Oct 2026 13:29:01 +0200
Subject: [PATCH 1/6] [analyzer] Skip LifetimeEnd nodes in
getNextStmtForDiagnostics
---
.../lib/StaticAnalyzer/Core/ExplodedGraph.cpp | 3 ++
.../test/Analysis/lifetime-end-path-notes.cpp | 51 +++++++++++++++++++
2 files changed, 54 insertions(+)
create mode 100644 clang/test/Analysis/lifetime-end-path-notes.cpp
diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index a73593baaa184e..11f65a295a5afe 100644
--- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -347,6 +347,9 @@ const Stmt *ExplodedNode::getNextStmtForDiagnostics() const {
for (const ExplodedNode *N = getFirstSucc(); N; N = N->getFirstSucc()) {
if (N->getLocation().isPurgeKind())
continue;
+ if (ProgramPoint P = N->getLocation(); P.getAs<LifetimeEnd>())
+ // P.dump();
+ continue;
if (const Stmt *S = N->getStmtForDiagnostics()) {
// Check if the statement is '?' or '&&'/'||'. These are "merges",
// not actual statement points.
diff --git a/clang/test/Analysis/lifetime-end-path-notes.cpp b/clang/test/Analysis/lifetime-end-path-notes.cpp
new file mode 100644
index 00000000000000..9fba6b7f845307
--- /dev/null
+++ b/clang/test/Analysis/lifetime-end-path-notes.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection,alpha.core.DanglingPtrDeref -analyzer-config cfg-lifetime=true -analyzer-output=text -verify %s
+
+void clang_analyzer_warnIfReached();
+
+// Enabling CFG lifetime-end elements should not cause regression in the
+// path notes. The loop exit path note must point to the next executed
+// statmeent and not back to the loop.
+void testPathNotesWithLoopScopeEnd() {
+ int *p = nullptr;
+ for (int i = 0; i < 3; ++i) {
+ // expected-note at -1 3 {{Loop condition is true. Entering loop body}}
+ // expected-note at -2 {{The value 2 is assigned to 'i'}}
+ // expected-note at -3 {{Loop condition is false. Execution continues on line 17}}
+ p = &i; // expected-note {{Value assigned to 'p'}}
+ }
+ // expected-note at -1 {{'i' is destroyed here}}
+ *p = 4;
+ // expected-warning at -1 {{Use of 'i' after its lifetime ended}}
+ // expected-note at -2 {{Use of 'i' after its lifetime ended}}
+}
+
+void testPathNotesWithBlockScopeEnd() {
+ int *p = nullptr;
+ {
+ int n = 0;
+ while (n < 3) {
+ // expected-note at -1 3 {{Loop condition is true. Entering loop body}}
+ // expected-note at -2 {{Loop condition is false. Execution continues on line 34}}
+ p = &n; // expected-note {{Value assigned to 'p'}}
+ ++n; // expected-note {{The value 2 is assigned to 'n'}}
+ }
+ }
+ // expected-note at -1 {{'n' is destroyed here}}
+ *p = 4;
+ // expected-warning at -1 {{Use of 'n' after its lifetime ended}}
+ // expected-note at -2 {{Use of 'n' after its lifetime ended}}
+}
+
+void testPathNotesWithWarnIfReached() {
+ {
+ int i = 0;
+ while (i < 3) {
+ // expected-note at -1 3 {{Loop condition is true. Entering loop body}}
+ // expected-note at -2 {{Loop condition is false. Execution continues on line 48}}
+ ++i;
+ }
+ }
+ clang_analyzer_warnIfReached();
+ // expected-warning at -1 {{REACHABLE}}
+ // expected-note at -2 {{REACHABLE}}
+}
>From 001e917e56d16b09898e4ab8928fa565aa6c6768 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Fri, 9 Oct 2026 22:55:12 +0200
Subject: [PATCH 2/6] Remove dump used for debugging.
---
clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index 11f65a295a5afe..510a3951bb5e12 100644
--- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -348,7 +348,6 @@ const Stmt *ExplodedNode::getNextStmtForDiagnostics() const {
if (N->getLocation().isPurgeKind())
continue;
if (ProgramPoint P = N->getLocation(); P.getAs<LifetimeEnd>())
- // P.dump();
continue;
if (const Stmt *S = N->getStmtForDiagnostics()) {
// Check if the statement is '?' or '&&'/'||'. These are "merges",
>From 14091be69090bbace9446e28cd1ba218de44f85a Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Fri, 9 Oct 2026 23:38:30 +0200
Subject: [PATCH 3/6] Do not assign getLocation.getAs to variable.
---
clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index 510a3951bb5e12..ef1311709cf9fe 100644
--- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -347,7 +347,7 @@ const Stmt *ExplodedNode::getNextStmtForDiagnostics() const {
for (const ExplodedNode *N = getFirstSucc(); N; N = N->getFirstSucc()) {
if (N->getLocation().isPurgeKind())
continue;
- if (ProgramPoint P = N->getLocation(); P.getAs<LifetimeEnd>())
+ if (N->getLocation().getAs<LifetimeEnd>())
continue;
if (const Stmt *S = N->getStmtForDiagnostics()) {
// Check if the statement is '?' or '&&'/'||'. These are "merges",
>From aecd0a6b76e989c9015d0606eb2f00f455484a76 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Fri, 9 Oct 2026 23:44:59 +0200
Subject: [PATCH 4/6] Break RUN line and updated expected-note with correct
line number.
---
clang/test/Analysis/lifetime-end-path-notes.cpp | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/clang/test/Analysis/lifetime-end-path-notes.cpp b/clang/test/Analysis/lifetime-end-path-notes.cpp
index 9fba6b7f845307..aa30eb0f477548 100644
--- a/clang/test/Analysis/lifetime-end-path-notes.cpp
+++ b/clang/test/Analysis/lifetime-end-path-notes.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection,alpha.core.DanglingPtrDeref -analyzer-config cfg-lifetime=true -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection,alpha.core.DanglingPtrDeref\
+// RUN: -analyzer-config cfg-lifetime=true -analyzer-output=text -verify %s
void clang_analyzer_warnIfReached();
@@ -10,7 +11,7 @@ void testPathNotesWithLoopScopeEnd() {
for (int i = 0; i < 3; ++i) {
// expected-note at -1 3 {{Loop condition is true. Entering loop body}}
// expected-note at -2 {{The value 2 is assigned to 'i'}}
- // expected-note at -3 {{Loop condition is false. Execution continues on line 17}}
+ // expected-note at -3 {{Loop condition is false. Execution continues on line 18}}
p = &i; // expected-note {{Value assigned to 'p'}}
}
// expected-note at -1 {{'i' is destroyed here}}
@@ -25,7 +26,7 @@ void testPathNotesWithBlockScopeEnd() {
int n = 0;
while (n < 3) {
// expected-note at -1 3 {{Loop condition is true. Entering loop body}}
- // expected-note at -2 {{Loop condition is false. Execution continues on line 34}}
+ // expected-note at -2 {{Loop condition is false. Execution continues on line 35}}
p = &n; // expected-note {{Value assigned to 'p'}}
++n; // expected-note {{The value 2 is assigned to 'n'}}
}
@@ -41,7 +42,7 @@ void testPathNotesWithWarnIfReached() {
int i = 0;
while (i < 3) {
// expected-note at -1 3 {{Loop condition is true. Entering loop body}}
- // expected-note at -2 {{Loop condition is false. Execution continues on line 48}}
+ // expected-note at -2 {{Loop condition is false. Execution continues on line 49}}
++i;
}
}
>From 2103055c81111006c46877ceae9d071893be3767 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Fri, 9 Oct 2026 23:48:31 +0200
Subject: [PATCH 5/6] Move expected-note to the enclosing brace.
---
clang/test/Analysis/lifetime-end-path-notes.cpp | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/clang/test/Analysis/lifetime-end-path-notes.cpp b/clang/test/Analysis/lifetime-end-path-notes.cpp
index aa30eb0f477548..76e2b6ae91deb3 100644
--- a/clang/test/Analysis/lifetime-end-path-notes.cpp
+++ b/clang/test/Analysis/lifetime-end-path-notes.cpp
@@ -11,10 +11,9 @@ void testPathNotesWithLoopScopeEnd() {
for (int i = 0; i < 3; ++i) {
// expected-note at -1 3 {{Loop condition is true. Entering loop body}}
// expected-note at -2 {{The value 2 is assigned to 'i'}}
- // expected-note at -3 {{Loop condition is false. Execution continues on line 18}}
+ // expected-note at -3 {{Loop condition is false. Execution continues on line 17}}
p = &i; // expected-note {{Value assigned to 'p'}}
- }
- // expected-note at -1 {{'i' is destroyed here}}
+ } // expected-note {{'i' is destroyed here}}
*p = 4;
// expected-warning at -1 {{Use of 'i' after its lifetime ended}}
// expected-note at -2 {{Use of 'i' after its lifetime ended}}
@@ -26,12 +25,11 @@ void testPathNotesWithBlockScopeEnd() {
int n = 0;
while (n < 3) {
// expected-note at -1 3 {{Loop condition is true. Entering loop body}}
- // expected-note at -2 {{Loop condition is false. Execution continues on line 35}}
+ // expected-note at -2 {{Loop condition is false. Execution continues on line 33}}
p = &n; // expected-note {{Value assigned to 'p'}}
++n; // expected-note {{The value 2 is assigned to 'n'}}
}
- }
- // expected-note at -1 {{'n' is destroyed here}}
+ } // expected-note {{'n' is destroyed here}}
*p = 4;
// expected-warning at -1 {{Use of 'n' after its lifetime ended}}
// expected-note at -2 {{Use of 'n' after its lifetime ended}}
@@ -42,7 +40,7 @@ void testPathNotesWithWarnIfReached() {
int i = 0;
while (i < 3) {
// expected-note at -1 3 {{Loop condition is true. Entering loop body}}
- // expected-note at -2 {{Loop condition is false. Execution continues on line 49}}
+ // expected-note at -2 {{Loop condition is false. Execution continues on line 47}}
++i;
}
}
>From dc45a4e6c1646bad84490996407f8b0a96212605 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Fri, 9 Oct 2026 23:57:53 +0200
Subject: [PATCH 6/6] Fix indentaiton.
---
clang/test/Analysis/lifetime-end-path-notes.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/test/Analysis/lifetime-end-path-notes.cpp b/clang/test/Analysis/lifetime-end-path-notes.cpp
index 76e2b6ae91deb3..ca374ce7997558 100644
--- a/clang/test/Analysis/lifetime-end-path-notes.cpp
+++ b/clang/test/Analysis/lifetime-end-path-notes.cpp
@@ -24,8 +24,8 @@ void testPathNotesWithBlockScopeEnd() {
{
int n = 0;
while (n < 3) {
- // expected-note at -1 3 {{Loop condition is true. Entering loop body}}
- // expected-note at -2 {{Loop condition is false. Execution continues on line 33}}
+ // expected-note at -1 3 {{Loop condition is true. Entering loop body}}
+ // expected-note at -2 {{Loop condition is false. Execution continues on line 33}}
p = &n; // expected-note {{Value assigned to 'p'}}
++n; // expected-note {{The value 2 is assigned to 'n'}}
}
@@ -39,8 +39,8 @@ void testPathNotesWithWarnIfReached() {
{
int i = 0;
while (i < 3) {
- // expected-note at -1 3 {{Loop condition is true. Entering loop body}}
- // expected-note at -2 {{Loop condition is false. Execution continues on line 47}}
+ // expected-note at -1 3 {{Loop condition is true. Entering loop body}}
+ // expected-note at -2 {{Loop condition is false. Execution continues on line 47}}
++i;
}
}
More information about the cfe-commits
mailing list