https://github.com/benedekaibas updated 
https://github.com/llvm/llvm-project/pull/215651

>From 0c78792ca93f6a76ed460cbde327fdec9393a936 Mon Sep 17 00:00:00 2001
From: benedekaibas <[email protected]>
Date: Tue, 11 Aug 2026 22:22:07 +0200
Subject: [PATCH 1/4] [analyzer] Only underline the parameter that is bound to
 the return value

---
 .../Checkers/UseAfterLifetimeEnd.cpp          | 24 +++++++++++++------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp 
b/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp
index a9065352adae6..de89836ee5dc2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp
@@ -43,20 +43,30 @@ class UseAfterLifetimeEndBRVisitor : public 
BugReporterVisitor {
 
 } // namespace
 
-static const Expr *getLifetimeBoundArg(const Expr *RetExpr) {
+static const Expr *getLifetimeBoundArg(const Expr *RetExpr,
+                                       const MemRegion *Region,
+                                       const ExplodedNode *N) {
   const CallExpr *Expr = dyn_cast_or_null<CallExpr>(RetExpr);
   if (!Expr)
     return nullptr;
+
   const FunctionDecl *FD = Expr->getDirectCallee();
   if (!FD)
     return nullptr;
 
+  const MemRegion *BaseReg = Region->getBaseRegion();
+
   for (const ParmVarDecl *PVD : FD->parameters()) {
-    if (PVD->hasAttr<LifetimeBoundAttr>()) {
-      unsigned Idx = PVD->getFunctionScopeIndex();
-      if (Idx < Expr->getNumArgs())
-        return Expr->getArg(Idx);
-    }
+    if (!PVD->hasAttr<LifetimeBoundAttr>())
+      continue;
+    unsigned Idx = PVD->getFunctionScopeIndex();
+
+    if (Idx >= Expr->getNumArgs())
+      continue;
+
+    const MemRegion *R = N->getSVal(Expr->getArg(Idx)).getAsRegion();
+    if (R && R->getBaseRegion() == BaseReg)
+      return Expr->getArg(Idx);
   }
   return nullptr;
 }
@@ -117,7 +127,7 @@ PathDiagnosticPieceRef 
UseAfterLifetimeEndBRVisitor::createSourcePiece(
     return nullptr;
 
   const Expr *RetExpr = dyn_cast_or_null<Expr>(S);
-  const Expr *Arg = getLifetimeBoundArg(RetExpr);
+  const Expr *Arg = getLifetimeBoundArg(RetExpr, SourceRegion, N);
 
   PathDiagnosticLocation Pos;
 

>From f103f33155dd64dc7ae0be45ce0f255318c61e61 Mon Sep 17 00:00:00 2001
From: benedekaibas <[email protected]>
Date: Wed, 12 Aug 2026 14:41:57 +0200
Subject: [PATCH 2/4] Add test case for testing highlighting.

---
 clang/test/Analysis/lifetime-bound.cpp | 35 +++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/clang/test/Analysis/lifetime-bound.cpp 
b/clang/test/Analysis/lifetime-bound.cpp
index d29c37f639993..e34796009c299 100644
--- a/clang/test/Analysis/lifetime-bound.cpp
+++ b/clang/test/Analysis/lifetime-bound.cpp
@@ -1,6 +1,7 @@
 // RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugLifetimeModeling
 \
 // RUN:   -analyzer-config cfg-lifetime=true -analyzer-output=text -verify %s
-
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugLifetimeModeling
 \
+// RUN:   -analyzer-output=text %s 2>&1 | FileCheck %s
 struct A {};
 
 struct Pair {
@@ -410,3 +411,35 @@ void no_dangling_by_value_argument() {
   // The returned reference does not dangle.
   takes_by_value(BoundToSelf());
 }
+
+int multi_params_annotated(int *p_one [[clang::lifetimebound]], int *p_two 
[[clang::lifetimebound]]);
+
+int test_multi_param_highlight() {
+  int local_one = 1, local_two = 2;
+  // expected-note@-1 {{'local_one' initialized here}}
+  // expected-note@-2 {{'local_two' initialized here}}
+  return multi_params_annotated(&local_one, &local_two);
+  // expected-warning@-1 {{address of stack memory associated with local 
variable 'local_one' returned}}
+  // expected-warning@-2 {{address of stack memory associated with local 
variable 'local_two' returned}}
+  // expected-warning@-3 {{Returning value bound to 'local_one' that will go 
out of scope}}
+  // expected-note@-4    {{Value's lifetime bound to the lifetime of 
'local_one' here}}
+  // expected-note@-5    {{Lifetime of 'local_one' ended here}}
+  // expected-warning@-6 {{Returning value bound to 'local_two' that will go 
out of scope}}
+  // expected-note@-7    {{Value's lifetime bound to the lifetime of 
'local_two' here}}
+  // expected-note@-8    {{Lifetime of 'local_two' ended here}}
+
+  // CHECK: :[[@LINE-10]]:33: note: Value's lifetime bound to the lifetime of 
'local_one' here
+  // CHECK-NEXT: [[@LINE-14]] | int local_one = 1, local_two = 2;
+  // CHECK-NEXT:                ~~~~~~~~~~~~~~~~~
+  // CHECK-NEXT: [[@LINE-15]] | // expected{{-}}note@-1 {{.*}}
+  // CHECK-NEXT: [[@LINE-15]] | // expected{{-}}note@-2 {{.*}}
+  // CHECK-NEXT: [[@LINE-15]] | return multi_params_annotated(&local_one, 
&local_two);
+  // CHECK-NEXT:                                              ^~~~~~~~~~
+  // CHECK: :[[@LINE-17]]:45: note: Value's lifetime bound to the lifetime of 
'local_two' here
+  // CHECK-NEXT: [[@LINE-21]] | int local_one = 1, local_two = 2;
+  // CHECK-NEXT:                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  // CHECK-NEXT: [[@LINE-22]] | // expected{{-}}note@-1 {{.*}}
+  // CHECK-NEXT: [[@LINE-22]] | // expected{{-}}note@-2 {{.*}}
+  // CHECK-NEXT: [[@LINE-22]] | return multi_params_annotated(&local_one, 
&local_two);
+  // CHECK-NEXT:                                                          
^~~~~~~~~~
+}

>From 8a6a4bf0d9c0f1316fa61697c0fbd76165a2c1fa Mon Sep 17 00:00:00 2001
From: benedekaibas <[email protected]>
Date: Wed, 12 Aug 2026 23:17:15 +0200
Subject: [PATCH 3/4] Rewrite CHECK lines.

---
 clang/test/Analysis/lifetime-bound.cpp | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/clang/test/Analysis/lifetime-bound.cpp 
b/clang/test/Analysis/lifetime-bound.cpp
index e34796009c299..d54116bc65314 100644
--- a/clang/test/Analysis/lifetime-bound.cpp
+++ b/clang/test/Analysis/lifetime-bound.cpp
@@ -428,18 +428,10 @@ int test_multi_param_highlight() {
   // expected-note@-7    {{Value's lifetime bound to the lifetime of 
'local_two' here}}
   // expected-note@-8    {{Lifetime of 'local_two' ended here}}
 
-  // CHECK: :[[@LINE-10]]:33: note: Value's lifetime bound to the lifetime of 
'local_one' here
-  // CHECK-NEXT: [[@LINE-14]] | int local_one = 1, local_two = 2;
-  // CHECK-NEXT:                ~~~~~~~~~~~~~~~~~
-  // CHECK-NEXT: [[@LINE-15]] | // expected{{-}}note@-1 {{.*}}
-  // CHECK-NEXT: [[@LINE-15]] | // expected{{-}}note@-2 {{.*}}
-  // CHECK-NEXT: [[@LINE-15]] | return multi_params_annotated(&local_one, 
&local_two);
-  // CHECK-NEXT:                                              ^~~~~~~~~~
-  // CHECK: :[[@LINE-17]]:45: note: Value's lifetime bound to the lifetime of 
'local_two' here
-  // CHECK-NEXT: [[@LINE-21]] | int local_one = 1, local_two = 2;
-  // CHECK-NEXT:                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  // CHECK-NEXT: [[@LINE-22]] | // expected{{-}}note@-1 {{.*}}
-  // CHECK-NEXT: [[@LINE-22]] | // expected{{-}}note@-2 {{.*}}
-  // CHECK-NEXT: [[@LINE-22]] | return multi_params_annotated(&local_one, 
&local_two);
-  // CHECK-NEXT:                                                          
^~~~~~~~~~
+  // CHECK: note: Value's lifetime bound to the lifetime of 'local_one' here
+  // CHECK: return multi_params_annotated(&local_one, &local_two);
+  // CHECK-NEXT:                          ^~~~~~~~~~
+  // CHECK: note: Value's lifetime bound to the lifetime of 'local_two' here
+  // CHECK: return multi_params_annotated(&local_one, &local_two);
+  // CHECK-NEXT:                                      ^~~~~~~~~~
 }

>From 6163d53ac079859ae65974b8c194c282b0145811 Mon Sep 17 00:00:00 2001
From: benedekaibas <[email protected]>
Date: Thu, 13 Aug 2026 17:46:24 +0200
Subject: [PATCH 4/4] Add test case.

---
 clang/test/Analysis/lifetime-bound.cpp | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/clang/test/Analysis/lifetime-bound.cpp 
b/clang/test/Analysis/lifetime-bound.cpp
index d54116bc65314..cd31c37aef16c 100644
--- a/clang/test/Analysis/lifetime-bound.cpp
+++ b/clang/test/Analysis/lifetime-bound.cpp
@@ -430,8 +430,23 @@ int test_multi_param_highlight() {
 
   // CHECK: note: Value's lifetime bound to the lifetime of 'local_one' here
   // CHECK: return multi_params_annotated(&local_one, &local_two);
-  // CHECK-NEXT:                          ^~~~~~~~~~
+  // CHECK-NEXT:{{\|                                 \^~~~~~~~~~$}}
   // CHECK: note: Value's lifetime bound to the lifetime of 'local_two' here
   // CHECK: return multi_params_annotated(&local_one, &local_two);
-  // CHECK-NEXT:                                      ^~~~~~~~~~
+  // CHECK-NEXT:{{\|                                             \^~~~~~~~~~$}}
+}
+
+int global_var;
+int test_correct_param_highlight() {
+  int local_n = 5;
+  // expected-note@-1 {{'local_n' initialized here}}
+  return multi_params_annotated(&global_var, &local_n);
+  // expected-warning@-1 {{address of stack memory associated with local 
variable 'local_n' returned}}
+  // expected-warning@-2 {{Returning value bound to 'local_n' that will go out 
of scope}}
+  // expected-note@-3    {{Value's lifetime bound to the lifetime of 'local_n' 
here}}
+  // expected-note@-4    {{Lifetime of 'local_n' ended here}}
+
+  // CHECK: note: Value's lifetime bound to the lifetime of 'local_n' here
+  // CHECK: return multi_params_annotated(&global_var, &local_n);
+  // CHECK-NEXT:{{\|                                              \^~~~~~~~$}}
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to