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

None

>From 55b52d314f3ee005ba8910d800c20761ad9ffe66 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <[email protected]>
Date: Sun, 18 Jan 2026 11:49:39 +0000
Subject: [PATCH] range based for loops

---
 .../LifetimeSafety/LifetimeAnnotations.cpp    |  8 +++
 clang/lib/Sema/SemaAttr.cpp                   | 10 ++--
 .../Sema/warn-lifetime-analysis-nocfg.cpp     | 57 +++++++++++++++++--
 3 files changed, 65 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp 
b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
index 2772fe20de19b..2ddd4c72c30f4 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
@@ -99,6 +99,14 @@ bool shouldTrackImplicitObjectArg(const CXXMethodDecl 
*Callee) {
   if (!isGslPointerType(Callee->getFunctionObjectParameterType()) &&
       !isGslOwnerType(Callee->getFunctionObjectParameterType()))
     return false;
+
+  // Track dereference operator for GSL pointers in STL.
+  if (isGslPointerType(Callee->getFunctionObjectParameterType()))
+    if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Callee))
+      if (MD->getOverloadedOperator() == OverloadedOperatorKind::OO_Star ||
+          MD->getOverloadedOperator() == OverloadedOperatorKind::OO_Arrow)
+        return true;
+
   if (isPointerLikeType(Callee->getReturnType())) {
     if (!Callee->getIdentifier())
       return false;
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 7729c113e422e..d98bcebbea8d7 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -138,12 +138,12 @@ void Sema::inferGslPointerAttribute(NamedDecl *ND,
       "unordered_multimap",
   };
 
-  static const llvm::StringSet<> Iterators{"iterator", "const_iterator",
-                                           "reverse_iterator",
-                                           "const_reverse_iterator"};
+  static const llvm::StringSet<> Iterators{
+      "iterator",         "const_iterator",
+      "reverse_iterator", "const_reverse_iterator",
+      "__wrap_iter",      "__normal_iterator"};
 
-  if (Parent->isInStdNamespace() && Iterators.count(ND->getName()) &&
-      Containers.count(Parent->getName()))
+  if (Parent->isInStdNamespace() && Iterators.count(ND->getName()))
     addGslOwnerPointerAttributeIfNotExisting<PointerAttr>(Context,
                                                           UnderlyingRecord);
 }
diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp 
b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index 7fdc493dbd17a..7830017245b46 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -911,10 +911,13 @@ struct MySpan {
   MySpan(const std::vector<T>& v);
   ~MySpan();
   using iterator = std::iterator<T>;
-  iterator begin() const [[clang::lifetimebound]];
+  // FIXME: It is not possible to annotate accessor methods of non-owning view 
types.
+  // Clang should provide another annotation to mark such functions as 
'transparent'.
+  iterator begin() const;
 };
+// FIXME: Same as above.
 template <typename T>
-typename MySpan<T>::iterator ReturnFirstIt(const MySpan<T>& v 
[[clang::lifetimebound]]);
+typename MySpan<T>::iterator ReturnFirstIt(const MySpan<T>& v);
 
 void test4() {
   std::vector<int> v{1};
@@ -926,15 +929,59 @@ void test4() {
   // Ideally, we would diagnose the following case, but due to implementation
   // constraints, we do not.
   const int& t4 = *MySpan<int>(std::vector<int>{}).begin();
+  use(t1, t2, t4);
 
-  // FIXME: Detect this using the CFG-based lifetime analysis (constructor of 
a pointer).
-  auto it1 = MySpan<int>(v).begin(); // expected-warning {{temporary whose 
address is use}}
-  auto it2 = ReturnFirstIt(MySpan<int>(v)); // expected-warning {{temporary 
whose address is used}}
+  auto it1 = MySpan<int>(v).begin();
+  auto it2 = ReturnFirstIt(MySpan<int>(v));
   use(it1, it2);
 }
 
 } // namespace LifetimeboundInterleave
 
+namespace range_based_for_loop_variables {
+std::string_view test_view_loop_var(std::vector<std::string> strings) {
+  for (std::string_view s : strings) {  // cfg-warning {{address of stack 
memory is returned later}} 
+    return s; //cfg-note {{returned here}}
+  }
+  return "";
+}
+
+const char* test_view_loop_var_with_data(std::vector<std::string> strings) {
+  for (std::string_view s : strings) {  // cfg-warning {{address of stack 
memory is returned later}} 
+    return s.data(); //cfg-note {{returned here}}
+  }
+  return "";
+}
+
+std::string_view test_no_error_for_views(std::vector<std::string_view> views) {
+  for (std::string_view s : views) {
+    return s;
+  }
+  return "";
+}
+
+std::string_view test_string_ref_var(std::vector<std::string> strings) {
+  for (const std::string& s : strings) {  // cfg-warning {{address of stack 
memory is returned later}} 
+    return s; //cfg-note {{returned here}}
+  }
+  return "";
+}
+
+std::string_view test_opt_strings(std::optional<std::vector<std::string>> 
strings_or) {
+  for (const std::string& s : *strings_or) {  // cfg-warning {{address of 
stack memory is returned later}} 
+    return s; //cfg-note {{returned here}}
+  }
+  return "";
+}
+} // namespace range_based_for_loop_variables
+
+namespace iterator_arrow {
+std::string_view test(std::vector<std::string> views) {
+  return views.begin()->data(); // expected-warning {{address of stack memory 
associated with parameter 'views' returned}} \
+                                // cfg-warning {{address of stack memory is 
returned later}} cfg-note {{returned here}}
+}
+} // namespace iterator_arrow
+
 namespace GH120206 {
 struct S {
   std::string_view s;

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

Reply via email to