https://github.com/aeft updated https://github.com/llvm/llvm-project/pull/186902

>From 28a594841caba6bcc05cd1633b44575a59f0e21b Mon Sep 17 00:00:00 2001
From: Alex Wang <[email protected]>
Date: Mon, 16 Mar 2026 15:10:38 -0700
Subject: [PATCH 1/2] [LifetimeSafety] Add origin tracking for array

---
 .../Analyses/LifetimeSafety/FactsGenerator.h  |   1 +
 .../LifetimeSafety/FactsGenerator.cpp         |  16 ++-
 .../Sema/warn-lifetime-analysis-nocfg.cpp     |   5 +-
 .../Sema/warn-lifetime-safety-suggestions.cpp |  12 ++
 clang/test/Sema/warn-lifetime-safety.cpp      | 114 ++++++++++++++++++
 5 files changed, 145 insertions(+), 3 deletions(-)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
index 9bcf5193ef8fc..dfcbdc7d73007 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
@@ -51,6 +51,7 @@ class FactsGenerator : public 
ConstStmtVisitor<FactsGenerator> {
   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE);
   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE);
   void VisitLambdaExpr(const LambdaExpr *LE);
+  void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE);
 
 private:
   OriginList *getOriginsList(const ValueDecl &D);
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 888176f09c9b9..3259505584c9f 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -296,9 +296,13 @@ void FactsGenerator::VisitImplicitCastExpr(const 
ImplicitCastExpr *ICE) {
     if (Dest && Src && Dest->getLength() == Src->getLength())
       flow(Dest, Src, /*Kill=*/true);
     return;
+  case CK_ArrayToPointerDecay:
+    assert(Src && "Array expression should have origins as it is GL value");
+    CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
+        Dest->getOuterOriginID(), Src->getOuterOriginID(), /*Kill=*/true));
+    return;
   case CK_FunctionToPointerDecay:
   case CK_BuiltinFnToFnPtr:
-  case CK_ArrayToPointerDecay:
     // Ignore function-to-pointer decays.
     return;
   default:
@@ -470,6 +474,16 @@ void FactsGenerator::VisitLambdaExpr(const LambdaExpr *LE) 
{
   }
 }
 
+void FactsGenerator::VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE) {
+  assert(ASE->isGLValue() && "Array subscript should be a GL value");
+  OriginList *Dst = getOriginsList(*ASE);
+  assert(Dst && "Array subscript should have origins as it is a GL value");
+  OriginList *Src = getOriginsList(*ASE->getBase());
+  assert(Src && "Base of array subscript should have origins");
+  CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
+      Dst->getOuterOriginID(), Src->getOuterOriginID(), /*Kill=*/true));
+}
+
 bool FactsGenerator::escapesViaReturn(OriginID OID) const {
   return llvm::any_of(EscapesInCurrentBlock, [OID](const Fact *F) {
     if (const auto *EF = F->getAs<ReturnEscapeFact>())
diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp 
b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index 3305e9e270d86..c4cc07e118763 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -77,8 +77,9 @@ struct Y {
 };
 
 void dangligGslPtrFromTemporary() {
-  MyIntPointer p = Y{}.a; // TODO
-  (void)p;
+  MyIntPointer p = Y{}.a; // cfg-warning {{object whose reference is captured 
does not live long enough}} \
+                          // cfg-note {{destroyed here}}
+  (void)p;                // cfg-note {{later used here}}
 }
 
 struct DanglingGslPtrField {
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp 
b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index b7e6c5951ba8b..754088e2384c8 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -423,3 +423,15 @@ auto implicit_value_capture(int integer,
   return [=]() { Foo(integer, ptr, ref, view); }; // expected-note 2 {{param 
returned here}}
 }
 } // namespace lambda_captures
+
+namespace array {
+
+struct MemberArrayReturn {
+  int arr[10];
+
+  int* getFirst() { // expected-warning {{implicit this in intra-TU function 
should be marked [[clang::lifetimebound]]}}
+    return &arr[0]; // expected-note {{param returned here}}
+  }
+};
+
+} // namespace array
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index 7fec336fad8be..43781ccc01a85 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -1980,3 +1980,117 @@ void outer_pointer_outlives_inner_pointee() {
 }
 
 } // namespace LoopLocalPointers
+
+namespace array {
+
+void element_use_after_scope() {
+  int* p;
+  {
+    int a[10]{};
+    p = &a[2]; // expected-warning {{object whose reference is captured does 
not live long enough}}
+  }            // expected-note {{destroyed here}}
+  (void)*p;    // expected-note {{later used here}}
+}
+
+int* element_use_after_return() {
+  int a[10]{};
+  int* p = &a[0]; // expected-warning {{address of stack memory is returned 
later}}
+  return p;       // expected-note {{returned here}}
+}
+
+void element_use_same_scope() {
+  int a[10]{};
+  int* p = &a[0];
+  (void)*p;
+}
+
+void element_reassigned_safe() {
+  int safe[10]{};
+  int* p;
+  {
+    int a[10]{};
+    p = &a[0];
+  }
+  p = &safe[0]; // rescued
+  (void)*p;
+}
+
+void multidimensional_use_after_scope() {
+  int* p;
+  {
+    int a[3][4]{};
+    p = &a[1][2]; // expected-warning {{object whose reference is captured 
does not live long enough}}
+  }               // expected-note {{destroyed here}}
+  (void)*p;       // expected-note {{later used here}}
+}
+
+void member_array_element_use_after_scope() {
+  struct S {
+    int arr[10];
+    int b;
+  };
+  int* p;
+  {
+    S s;
+    p = &s.arr[0]; // expected-warning {{object whose reference is captured 
does not live long enough}}
+  }                // expected-note {{destroyed here}}
+  (void)*p;        // expected-note {{later used here}}
+}
+
+void array_of_pointers_use_after_scope() {
+  int** p;
+  {
+    int x = 0;
+    int* a[10] = {&x};
+    p = a;  // expected-warning {{object whose reference is captured does not 
live long enough}}
+  }         // expected-note {{destroyed here}}
+  (void)*p; // expected-note {{later used here}}
+}
+
+void reversed_subscript_use_after_scope() {
+  int* p;
+  {
+    int a[10]{};
+    p = &(0[a]); // expected-warning {{object whose reference is captured does 
not live long enough}}
+  }              // expected-note {{destroyed here}}
+  (void)*p;      // expected-note {{later used here}}
+}
+
+int* return_decayed_array() {
+  int a[10]{};
+  int *p = a; // expected-warning {{address of stack memory is returned later}}
+  return p;   // expected-note {{returned here}}
+}
+
+int* param_array_element(int a[], int n) {
+  return &a[n];
+}
+
+int* static_array() {
+  static int a[10]{};
+  return &a[1];
+}
+
+// FIXME: Pointer arithmetic is not yet tracked.
+void pointer_arithmetic_use_after_scope() {
+  int* p;
+  {
+    int a[10]{};
+    p = a + 5;
+  }
+  (void)*p; // should warn
+}
+
+// FIXME: Reading a pointer value stored inside an array element
+// is not yet tracked.
+void read_pointer_from_array_element_use_after_scope() {
+  int* q;
+  {
+    int x = 0;
+    int* arr[10] = {&x};
+    q = arr[0];
+  }
+  (void)*q; // should warn
+}
+
+} // namespace array

>From 1f961acd9f688cd52655507a94d8de4db08f3cde Mon Sep 17 00:00:00 2001
From: Alex Wang <[email protected]>
Date: Tue, 17 Mar 2026 16:08:01 -0700
Subject: [PATCH 2/2] address review comments

---
 .../Sema/warn-lifetime-safety-suggestions.cpp |  4 ++++
 clang/test/Sema/warn-lifetime-safety.cpp      | 24 ++++++++++++-------
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp 
b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 754088e2384c8..22c4222022ebf 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -432,6 +432,10 @@ struct MemberArrayReturn {
   int* getFirst() { // expected-warning {{implicit this in intra-TU function 
should be marked [[clang::lifetimebound]]}}
     return &arr[0]; // expected-note {{param returned here}}
   }
+
+  int* getData() { // expected-warning {{implicit this in intra-TU function 
should be marked [[clang::lifetimebound]]}}
+    return arr;    // expected-note {{param returned here}}
+  }
 };
 
 } // namespace array
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index 43781ccc01a85..bd09bb70e9a11 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -2011,7 +2011,7 @@ void element_reassigned_safe() {
     int a[10]{};
     p = &a[0];
   }
-  p = &safe[0]; // rescued
+  p = &safe[0]; // Rescued.
   (void)*p;
 }
 
@@ -2040,8 +2040,7 @@ void member_array_element_use_after_scope() {
 void array_of_pointers_use_after_scope() {
   int** p;
   {
-    int x = 0;
-    int* a[10] = {&x};
+    int* a[10]{};
     p = a;  // expected-warning {{object whose reference is captured does not 
live long enough}}
   }         // expected-note {{destroyed here}}
   (void)*p; // expected-note {{later used here}}
@@ -2078,19 +2077,28 @@ void pointer_arithmetic_use_after_scope() {
     int a[10]{};
     p = a + 5;
   }
-  (void)*p; // should warn
+  (void)*p; // Should warn.
 }
 
-// FIXME: Reading a pointer value stored inside an array element
-// is not yet tracked.
-void read_pointer_from_array_element_use_after_scope() {
+// FIXME: Copying a pointer value out of an array element is not tracked.
+void copy_pointer_from_array_use_after_scope() {
   int* q;
   {
     int x = 0;
     int* arr[10] = {&x};
     q = arr[0];
   }
-  (void)*q; // should warn
+  (void)*q; // Should warn.
+}
+
+// FIXME: A pointer inside an array becoming dangling is not detected.
+void pointer_in_array_use_after_scope() {
+  int* arr[10];
+  {
+    int x = 0;
+    arr[0] = &x;
+  }
+  (void)*arr[0]; // Should warn.
 }
 
 } // namespace array

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

Reply via email to