llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Haojian Wu (hokein)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/118078.diff


2 Files Affected:

- (modified) clang/lib/Sema/SemaAttr.cpp (+37-22) 
- (modified) clang/test/AST/attr-lifetime-capture-by.cpp (+16) 


``````````diff
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index d3cf42251be2e7..3279f4109a9c02 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -270,34 +270,49 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
 }
 
 void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
-  if (!FD)
+  auto *MD = dyn_cast_if_present<CXXMethodDecl>(FD);
+  if (!MD || !MD->getParent()->isInStdNamespace())
     return;
-  auto *MD = dyn_cast<CXXMethodDecl>(FD);
-  if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace())
+  auto Annotate = [this](const FunctionDecl *MD) {
+    // Do not infer if any parameter is explicitly annotated.
+    for (ParmVarDecl *PVD : MD->parameters())
+      if (PVD->hasAttr<LifetimeCaptureByAttr>())
+        return;
+    for (ParmVarDecl *PVD : MD->parameters()) {
+      // Methods in standard containers that capture values typically accept
+      // reference-type parameters, e.g., `void push_back(const T& value)`.
+      // We only apply the lifetime_capture_by attribute to parameters of
+      // pointer-like reference types (`const T&`, `T&&`).
+      if (PVD->getType()->isReferenceType() &&
+          sema::isPointerLikeType(PVD->getType().getNonReferenceType())) {
+        int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
+        PVD->addAttr(
+            LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));
+      }
+    }
+  };
+
+  if (!MD->getIdentifier()) {
+    static const llvm::StringSet<> MapLikeContainer{
+        "map",
+        "multimap",
+        "unordered_map",
+        "unordered_multimap",
+    };
+    // Infer for the map's operator []:
+    //    std::map<string_view, ...> m;
+    //    m[ReturnString(..)] = ...; // !dangling references in m.
+    if (MD->getOverloadedOperator() != OO_Subscript ||
+        !MapLikeContainer.contains(MD->getParent()->getName()))
+      return;
+    Annotate(MD);
     return;
-  // FIXME: Infer for operator[] for map-like containers. For example:
-  //    std::map<string_view, ...> m;
-  //    m[ReturnString(..)] = ...;
+  }
   static const llvm::StringSet<> CapturingMethods{"insert", "push",
                                                   "push_front", "push_back"};
   if (!CapturingMethods.contains(MD->getName()))
     return;
-  // Do not infer if any parameter is explicitly annotated.
-  for (ParmVarDecl *PVD : MD->parameters())
-    if (PVD->hasAttr<LifetimeCaptureByAttr>())
-      return;
-  for (ParmVarDecl *PVD : MD->parameters()) {
-    // Methods in standard containers that capture values typically accept
-    // reference-type parameters, e.g., `void push_back(const T& value)`.
-    // We only apply the lifetime_capture_by attribute to parameters of
-    // pointer-like reference types (`const T&`, `T&&`).
-    if (PVD->getType()->isReferenceType() &&
-        sema::isPointerLikeType(PVD->getType().getNonReferenceType())) {
-      int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
-      PVD->addAttr(
-          LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));
-    }
-  }
+  Annotate(MD);
 }
 
 void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) {
diff --git a/clang/test/AST/attr-lifetime-capture-by.cpp 
b/clang/test/AST/attr-lifetime-capture-by.cpp
index debad9b7204d72..71b348dac764bc 100644
--- a/clang/test/AST/attr-lifetime-capture-by.cpp
+++ b/clang/test/AST/attr-lifetime-capture-by.cpp
@@ -30,6 +30,12 @@ struct vector {
 
   void insert(iterator, T&&);
 };
+
+template <typename Key, typename Value>
+struct map {
+  Value& operator[](Key&& p);
+  Value& operator[](const Key& p);
+};
 } // namespace std
 
 // CHECK-NOT:   LifetimeCaptureByAttr
@@ -99,3 +105,13 @@ std::vector<int> ints;
 // CHECK-NEXT:           ParmVarDecl {{.*}} 'iterator'
 // CHECK-NEXT:           ParmVarDecl {{.*}} 'int &&'
 // CHECK-NOT:   LifetimeCaptureByAttr
+
+std::map<View, int> map;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct map definition 
implicit_instantiation
+
+// CHECK:       CXXMethodDecl {{.*}} operator[] 'int &(View &&)' 
implicit_instantiation
+// CHECK-NEXT:           ParmVarDecl {{.*}} p 'View &&'
+// CHECK-NEXT:               LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK:       CXXMethodDecl {{.*}} operator[] 'int &(const View &)' 
implicit_instantiation
+// CHECK-NEXT:           ParmVarDecl {{.*}} p 'const View &'
+// CHECK-NEXT:               LifetimeCaptureByAttr {{.*}} Implicit

``````````

</details>


https://github.com/llvm/llvm-project/pull/118078
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to