https://github.com/usx95 created 
https://github.com/llvm/llvm-project/pull/179227

None

>From 98c38f4ffedfb094efac96811910e1b9472a0ecf Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <[email protected]>
Date: Mon, 2 Feb 2026 13:02:13 +0000
Subject: [PATCH] stl algorithms lifetimebound

---
 .../LifetimeSafety/LifetimeAnnotations.cpp    | 33 +++++++++++++++++--
 clang/test/Sema/Inputs/lifetime-analysis.h    |  3 ++
 .../Sema/warn-lifetime-analysis-nocfg.cpp     | 23 +++++++++++++
 3 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp 
b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
index be33caf327802..ac1eb9db8a153 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
@@ -174,13 +174,41 @@ bool shouldTrackImplicitObjectArg(const CXXMethodDecl 
*Callee,
 }
 
 bool shouldTrackFirstArgument(const FunctionDecl *FD) {
-  if (!FD->getIdentifier() || FD->getNumParams() != 1)
+  if (!FD->getIdentifier() || FD->getNumParams() < 1)
     return false;
+  if (!FD->isInStdNamespace())
+    return false;
+  // Track std:: algorithm functions that return an iterator whose lifetime is
+  // bound to the first argument.
+  if (FD->getNumParams() >= 2 && FD->isInStdNamespace() &&
+      isGslPointerType(FD->getReturnType())) {
+    if (llvm::StringSwitch<bool>(FD->getName())
+            .Cases(
+                {
+                    "find",
+                    "find_if",
+                    "find_if_not",
+                    "find_first_of",
+                    "adjacent_find",
+                    "search",
+                    "find_end",
+                    "lower_bound",
+                    "upper_bound",
+                    "partition_point",
+                },
+                true)
+            .Default(false))
+      return true;
+  }
   const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl();
-  if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace())
+  if (!RD || !RD->isInStdNamespace())
     return false;
   if (!RD->hasAttr<PointerAttr>() && !RD->hasAttr<OwnerAttr>())
     return false;
+
+  if (FD->getNumParams() != 1)
+    return false;
+
   if (FD->getReturnType()->isPointerType() ||
       isGslPointerType(FD->getReturnType())) {
     return llvm::StringSwitch<bool>(FD->getName())
@@ -226,5 +254,4 @@ template <typename T> static bool isRecordWithAttr(QualType 
Type) {
 
 bool isGslPointerType(QualType QT) { return isRecordWithAttr<PointerAttr>(QT); 
}
 bool isGslOwnerType(QualType QT) { return isRecordWithAttr<OwnerAttr>(QT); }
-
 } // namespace clang::lifetimes
diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h 
b/clang/test/Sema/Inputs/lifetime-analysis.h
index 4f881d463ebcc..27882e68c1524 100644
--- a/clang/test/Sema/Inputs/lifetime-analysis.h
+++ b/clang/test/Sema/Inputs/lifetime-analysis.h
@@ -16,6 +16,9 @@ template<typename T> struct remove_reference       { typedef 
T type; };
 template<typename T> struct remove_reference<T &>  { typedef T type; };
 template<typename T> struct remove_reference<T &&> { typedef T type; };
 
+template< class InputIt, class T >
+InputIt find( InputIt first, InputIt last, const T& value );
+
 template<typename T>
 typename remove_reference<T>::type &&move(T &&t) noexcept;
 
diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp 
b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index c82cf41b07361..a58b446fe4c07 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -429,6 +429,29 @@ int *returnPtrToLocalArray() {
   return std::begin(a); // TODO
 }
 
+namespace lifetimebound_stl_algorithms {
+
+std::vector<std::string> GetTemporaryString();
+std::vector<std::string_view> GetTemporaryView();
+
+std::string_view test_str_local() {
+  std::vector<std::string> v;
+  return *std::find(v.begin(), // cfg-warning {{address of stack memory is 
returned later}} cfg-note {{returned here}}
+                    v.end(), "42");
+}
+std::string_view test_str_temporary() {
+  return *std::find(GetTemporaryString().begin(), // cfg-warning {{address of 
stack memory is returned later}} cfg-note {{returned here}}
+                    GetTemporaryString().end(), "42");
+}
+std::string_view test_view() {
+  std::vector<std::string_view> v;
+  return *std::find(v.begin(), v.end(), "42");
+}
+std::string_view test_view_local() {
+  return *std::find(GetTemporaryView().begin(), GetTemporaryView().end(), 
"42");
+}
+} // namespace lifetimebound_stl_algorithms
+
 struct ptr_wrapper {
   std::vector<int>::iterator member;
 };

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

Reply via email to