[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)

2024-12-02 Thread Haojian Wu via cfe-commits

https://github.com/hokein closed 
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


[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)

2024-12-02 Thread Haojian Wu via cfe-commits


@@ -270,34 +270,49 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
 }
 
 void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
-  if (!FD)
+  auto *MD = dyn_cast_if_present(FD);
+  if (!MD || !MD->getParent()->isInStdNamespace())
 return;
-  auto *MD = dyn_cast(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())
+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 m;
+//m[ReturnString(..)] = ...; // !dangling references in m.
+if (MD->getOverloadedOperator() != OO_Subscript ||
+!MapLikeContainer.contains(MD->getParent()->getName()))
+  return;

hokein wrote:

Done.

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


[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)

2024-12-02 Thread Haojian Wu via cfe-commits

https://github.com/hokein updated 
https://github.com/llvm/llvm-project/pull/118078

>From 4db8f43507d6d36ef1cfeabb4c308e781a1b061e Mon Sep 17 00:00:00 2001
From: Haojian Wu 
Date: Fri, 29 Nov 2024 11:07:56 +0100
Subject: [PATCH 1/2] [clang] Infer lifetime_capture_by for map's subscript
 operator.

---
 clang/lib/Sema/SemaAttr.cpp | 59 +
 clang/test/AST/attr-lifetime-capture-by.cpp | 16 ++
 2 files changed, 53 insertions(+), 22 deletions(-)

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(FD);
+  if (!MD || !MD->getParent()->isInStdNamespace())
 return;
-  auto *MD = dyn_cast(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())
+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 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 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())
-  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 
+struct map {
+  Value& operator[](Key&& p);
+  Value& operator[](const Key& p);
+};
 } // namespace std
 
 // CHECK-NOT:   LifetimeCaptureByAttr
@@ -99,3 +105,13 @@ std::vector ints;
 // CHECK-NEXT:   ParmVarDecl {{.*}} 'iterator'
 // CHECK-NEXT:   ParmVarDecl {{.*}} 'int &&'
 // CHECK-NOT:   LifetimeCaptureByAttr
+
+std::map 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

>From ce01d4b7566ce7d0a098155a71ac8b8ae40a7a7b Mon Sep 17 00:00:00 2001
From: Haojian Wu 
Date: Mon, 2 Dec 2024 09:24:41 +0100
Subject: [PATCH 2/2] Address review comment.

---
 clang/lib/Sema/Se

[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)

2024-11-29 Thread Utkarsh Saxena via cfe-commits


@@ -270,34 +270,49 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
 }
 
 void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
-  if (!FD)
+  auto *MD = dyn_cast_if_present(FD);
+  if (!MD || !MD->getParent()->isInStdNamespace())
 return;
-  auto *MD = dyn_cast(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())
+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 m;
+//m[ReturnString(..)] = ...; // !dangling references in m.
+if (MD->getOverloadedOperator() != OO_Subscript ||
+!MapLikeContainer.contains(MD->getParent()->getName()))
+  return;

usx95 wrote:

nit: early returns complicates this. Maybe simplify like:
```cpp
if (MD->getOverloadedOperator() == OO_Subscript &&
MapLikeContainer.contains(MD->getParent()->getName()))
  Annotate(MD);
return;
```


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


[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)

2024-11-29 Thread Utkarsh Saxena via cfe-commits

https://github.com/usx95 approved this pull request.

Thanks. LGTM.

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


[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)

2024-11-29 Thread Utkarsh Saxena via cfe-commits

https://github.com/usx95 edited 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


[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)

2024-11-29 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Haojian Wu (hokein)


Changes



---
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(FD);
+  if (!MD || !MD->getParent()->isInStdNamespace())
 return;
-  auto *MD = dyn_cast(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())
+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 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 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())
-  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 
+struct map {
+  Value& operator[](Key&& p);
+  Value& operator[](const Key& p);
+};
 } // namespace std
 
 // CHECK-NOT:   LifetimeCaptureByAttr
@@ -99,3 +105,13 @@ std::vector ints;
 // CHECK-NEXT:   ParmVarDecl {{.*}} 'iterator'
 // CHECK-NEXT:   ParmVarDecl {{.*}} 'int &&'
 // CHECK-NOT:   LifetimeCaptureByAttr
+
+std::map 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

``




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


[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)

2024-11-29 Thread Haojian Wu via cfe-commits

https://github.com/hokein created 
https://github.com/llvm/llvm-project/pull/118078

None

>From 18d56e847901653de9f84e256f30ec0e16ebca96 Mon Sep 17 00:00:00 2001
From: Haojian Wu 
Date: Fri, 29 Nov 2024 11:07:56 +0100
Subject: [PATCH] [clang] Infer lifetime_capture_by for map's subscript
 operator.

---
 clang/lib/Sema/SemaAttr.cpp | 59 +
 clang/test/AST/attr-lifetime-capture-by.cpp | 16 ++
 2 files changed, 53 insertions(+), 22 deletions(-)

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(FD);
+  if (!MD || !MD->getParent()->isInStdNamespace())
 return;
-  auto *MD = dyn_cast(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())
+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 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 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())
-  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 
+struct map {
+  Value& operator[](Key&& p);
+  Value& operator[](const Key& p);
+};
 } // namespace std
 
 // CHECK-NOT:   LifetimeCaptureByAttr
@@ -99,3 +105,13 @@ std::vector ints;
 // CHECK-NEXT:   ParmVarDecl {{.*}} 'iterator'
 // CHECK-NEXT:   ParmVarDecl {{.*}} 'int &&'
 // CHECK-NOT:   LifetimeCaptureByAttr
+
+std::map 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

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits