[clang] [clang] Infer lifetime_capture_by for STL containers (PR #117122)

2024-11-22 Thread LLVM Continuous Integration via cfe-commits

llvm-ci wrote:

LLVM Buildbot has detected a new failure on builder 
`openmp-offload-amdgpu-runtime` running on `omp-vega20-0` while building 
`clang` at step 6 "test-openmp".

Full details are available at: 
https://lab.llvm.org/buildbot/#/builders/30/builds/10839


Here is the relevant piece of the build log for the reference

```
Step 6 (test-openmp) failure: test (failure)
 TEST 'libomp :: tasking/issue-94260-2.c' FAILED 

Exit Code: -11

Command Output (stdout):
--
# RUN: at line 1
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/clang 
-fopenmp   -I 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src
 -I 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/openmp/runtime/test 
-L 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src
  -fno-omit-frame-pointer -I 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/openmp/runtime/test/ompt
 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c
 -o 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
 -lm -latomic && 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
# executed command: 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/clang 
-fopenmp -I 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src
 -I 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/openmp/runtime/test 
-L 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src
 -fno-omit-frame-pointer -I 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/openmp/runtime/test/ompt
 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c
 -o 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
 -lm -latomic
# note: command had no output on stdout or stderr
# executed command: 
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
# note: command had no output on stdout or stderr
# error: command failed with exit status: -11

--




```



https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -7,3 +7,106 @@ struct S {
 };
 
 // CHECK: CXXMethodDecl {{.*}}clang::lifetime_capture_by(a, b, global)
+
+// 
+// Infer annotation for STL container methods.
+// 
+namespace __gnu_cxx {
+template 
+struct basic_iterator {};
+}
+
+namespace std {
+template class allocator {};
+template >
+struct vector {
+  typedef __gnu_cxx::basic_iterator iterator;
+  iterator begin();
+
+  vector();
+
+  void push_back(const T&);
+  void push_back(T&&);
+
+  void insert(iterator, T&&);
+};
+} // namespace std
+struct [[gsl::Pointer()]] View {};
+std::vector views;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition 
implicit_instantiation
+// CHECK:   TemplateArgument type 'View'
+// CHECK-NOT:   LifetimeCaptureByAttr

hokein wrote:

Ah, I see. Thanks.

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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

https://github.com/usx95 closed https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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

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


https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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

https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -7,3 +7,106 @@ struct S {
 };
 
 // CHECK: CXXMethodDecl {{.*}}clang::lifetime_capture_by(a, b, global)
+
+// 
+// Infer annotation for STL container methods.
+// 
+namespace __gnu_cxx {
+template 
+struct basic_iterator {};
+}
+
+namespace std {
+template class allocator {};
+template >
+struct vector {
+  typedef __gnu_cxx::basic_iterator iterator;
+  iterator begin();
+
+  vector();
+
+  void push_back(const T&);
+  void push_back(T&&);
+
+  void insert(iterator, T&&);
+};
+} // namespace std
+struct [[gsl::Pointer()]] View {};
+std::vector views;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition 
implicit_instantiation
+// CHECK:   TemplateArgument type 'View'
+// CHECK-NOT:   LifetimeCaptureByAttr

usx95 wrote:

Well this is along the lines of not having capture by on values and only for 
view types. For example:
```
  std::vector strings;
  strings.push_back(std::string());
  strings.insert(strings.begin(), std::string());
```

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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

https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -7,3 +7,106 @@ struct S {
 };
 
 // CHECK: CXXMethodDecl {{.*}}clang::lifetime_capture_by(a, b, global)
+
+// 
+// Infer annotation for STL container methods.
+// 
+namespace __gnu_cxx {
+template 
+struct basic_iterator {};
+}
+
+namespace std {
+template class allocator {};
+template >
+struct vector {
+  typedef __gnu_cxx::basic_iterator iterator;
+  iterator begin();
+
+  vector();
+
+  void push_back(const T&);
+  void push_back(T&&);
+
+  void insert(iterator, T&&);
+};
+} // namespace std
+struct [[gsl::Pointer()]] View {};
+std::vector views;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition 
implicit_instantiation
+// CHECK:   TemplateArgument type 'View'
+// CHECK-NOT:   LifetimeCaptureByAttr

hokein wrote:

> That would add the annotation to all of its specializations which is not 
> something we want.

Can you give a counter example? 

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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

https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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

https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();

usx95 wrote:

Hmm. It can reproduce with `` include but not with handcrafted `vector` 
in lit tests. 

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();

hokein wrote:

hmm, this is strange. I tested it locally, it works for me.

```
$ cat /t/t6.cpp
#include 

template
struct [[gsl::Pointer]] Span {
  Span(const std::vector &V);
};

void use() {
  Span pp(std::vector{});
  std::vector> spans;
  spans.push_back(std::vector()); // warning.
}
$ ./bin/clang -Xclang -fsyntax-only -Wdangling-capture /t/t6.cpp

 <<<

/t/t6.cpp:9:16: warning: object backing the pointer will be destroyed at the 
end of the full-expression [-Wdangling-gsl]
9 |   Span pp(std::vector{});
  |^~
/t/t6.cpp:11:19: warning: object whose reference is captured by 'spans' will be 
destroyed at the end of the full-expression [-Wdangling-capture]
   11 |   spans.push_back(std::vector()); // warning.
  |   ^~
2 warnings generated.
/usr/bin/ld: /lib/x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x17): undefined reference to `main'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
```

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -7,3 +7,106 @@ struct S {
 };
 
 // CHECK: CXXMethodDecl {{.*}}clang::lifetime_capture_by(a, b, global)
+
+// 
+// Infer annotation for STL container methods.
+// 
+namespace __gnu_cxx {
+template 
+struct basic_iterator {};
+}
+
+namespace std {
+template class allocator {};
+template >
+struct vector {
+  typedef __gnu_cxx::basic_iterator iterator;
+  iterator begin();
+
+  vector();
+
+  void push_back(const T&);
+  void push_back(T&&);
+
+  void insert(iterator, T&&);
+};
+} // namespace std
+struct [[gsl::Pointer()]] View {};
+std::vector views;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition 
implicit_instantiation
+// CHECK:   TemplateArgument type 'View'
+// CHECK-NOT:   LifetimeCaptureByAttr

usx95 wrote:

No. That would add the annotation to all of its specializations which is not 
something we want.

Tested: Added an extra `// CHECK-NOT:   LifetimeCaptureByAttr` before the 
beginning of the tests as well.

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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

https://github.com/usx95 updated 
https://github.com/llvm/llvm-project/pull/117122

>From 9a57223b06a8331a0ef123739a430863dee19d98 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena 
Date: Thu, 21 Nov 2024 07:00:56 +
Subject: [PATCH 1/4] [clang] Infer lifetime_capture_by for STL containers

---
 clang/include/clang/Sema/Sema.h   |  3 +
 clang/lib/Sema/SemaAttr.cpp   | 34 
 clang/lib/Sema/SemaDecl.cpp   |  2 +
 clang/test/Sema/Inputs/lifetime-analysis.h|  5 ++
 .../warn-lifetime-analysis-capture-by.cpp | 79 +++
 5 files changed, 123 insertions(+)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6ea6c67447b6f0..9bafcfec5d4786 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1757,6 +1757,9 @@ class Sema final : public SemaBase {
   /// Add [[clang:::lifetimebound]] attr for std:: functions and methods.
   void inferLifetimeBoundAttribute(FunctionDecl *FD);
 
+  /// Add [[clang:::lifetime_capture(this)]] to STL container methods.
+  void inferLifetimeCaptureByAttribute(FunctionDecl *FD);
+
   /// Add [[gsl::Pointer]] attributes for std:: types.
   void inferGslPointerAttribute(TypedefNameDecl *TD);
 
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 9fbad7ed67ccbe..507f7c40d58782 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+  return RD->hasAttr();
+}
+
+void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
+  if (!FD)
+return;
+  auto *MD = dyn_cast(FD);
+  if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace())
+return;
+  static const llvm::StringSet<> CapturingMethods{"insert", "push",
+  "push_front", "push_back"};
+  if (!CapturingMethods.contains(MD->getName()))
+return;
+  for (ParmVarDecl *PVD : MD->parameters()) {
+if (PVD->hasAttr())
+  return;
+if (IsPointerLikeType(PVD->getType())) {
+  int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
+  PVD->addAttr(
+  LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));
+}
+  }
+}
+
 void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) {
   static const llvm::StringSet<> Nullable{
   "auto_ptr", "shared_ptr", "unique_ptr", "exception_ptr",
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index be570f3a1829d0..5b30d0f2c22d16 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -11913,6 +11913,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, 
FunctionDecl *NewFD,
   NamedDecl *OldDecl = nullptr;
   bool MayNeedOverloadableChecks = false;
 
+  inferLifetimeCaptureByAttribute(NewFD);
   // Merge or overload the declaration with an existing declaration of
   // the same name, if appropriate.
   if (!Previous.empty()) {
@@ -16716,6 +16717,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) 
{
 
   LazyProcessLifetimeCaptureByParams(FD);
   inferLifetimeBoundAttribute(FD);
+  inferLifetimeCaptureByAttribute(FD);
   AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD);
 
   // If C++ exceptions are enabled but we are told extern "C" functions cannot
diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h 
b/clang/test/Sema/Inputs/lifetime-analysis.h
index 41d1e2f074cc83..5c151385b1fe5a 100644
--- a/clang/test/Sema/Inputs/lifetime-analysis.h
+++ b/clang/test/Sema/Inputs/lifetime-analysis.h
@@ -49,6 +49,11 @@ struct vector {
vector(InputIterator first, InputIterator __last);
 
   T &at(int n);
+
+  void push_back(const T&);
+  void push_back(T&&);
+  
+  void insert(iterator, T&&);
 };
 
 template
diff --git a/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp 
b/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
index b3fde386b8616c..462cb2d3f3fd6e 100644
--- a/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
@@ -366,3 +366,82 @@ void use() {
   capture3(std::string(), x3); // expected-warning {{object whose reference is 
captured by 'x3' will be destroyed at the end of the full-expression}}
 }
 } // namespace temporary_views
+
+// 
+// Inferring annotation for STL containers
+// 
+namespace inferred_capture_by {
+const std::string* getLifetimeBoundPointer(const std::string &s 
[[clang::lifetimebound]

[clang] [clang] Infer lifetime_capture_by for STL containers (PR #117122)

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


@@ -7,3 +7,106 @@ struct S {
 };
 
 // CHECK: CXXMethodDecl {{.*}}clang::lifetime_capture_by(a, b, global)
+
+// 
+// Infer annotation for STL container methods.
+// 
+namespace __gnu_cxx {
+template 
+struct basic_iterator {};
+}
+
+namespace std {
+template class allocator {};
+template >
+struct vector {
+  typedef __gnu_cxx::basic_iterator iterator;
+  iterator begin();
+
+  vector();
+
+  void push_back(const T&);
+  void push_back(T&&);
+
+  void insert(iterator, T&&);
+};
+} // namespace std
+struct [[gsl::Pointer()]] View {};
+std::vector views;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition 
implicit_instantiation
+// CHECK:   TemplateArgument type 'View'
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (const View &)'
+// CHECK:   ParmVarDecl {{.*}} 'const View &'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (View &&)'
+// CHECK:   ParmVarDecl {{.*}} 'View &&'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+
+// CHECK:   CXXMethodDecl {{.*}} insert 'void (iterator, View &&)'
+// CHECK:   ParmVarDecl {{.*}} 'iterator'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK:   ParmVarDecl {{.*}} 'View &&'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+template  struct [[gsl::Pointer()]] ViewTemplate {};
+std::vector> templated_views;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition 
implicit_instantiation
+// CHECK:   TemplateArgument type 'ViewTemplate'
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (const ViewTemplate 
&)'
+// CHECK:   ParmVarDecl {{.*}} 'const ViewTemplate &'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (ViewTemplate &&)'
+// CHECK:   ParmVarDecl {{.*}} 'ViewTemplate &&'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+
+// CHECK:   CXXMethodDecl {{.*}} insert 'void (iterator, ViewTemplate 
&&)'
+// CHECK:   ParmVarDecl {{.*}} 'iterator'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK:   ParmVarDecl {{.*}} 'ViewTemplate &&'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+std::vector pointers;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition 
implicit_instantiation
+// CHECK:   TemplateArgument type 'int *'
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (int *const &)'
+// CHECK:   ParmVarDecl {{.*}} 'int *const &'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (int *&&)'
+// CHECK:   ParmVarDecl {{.*}} 'int *&&'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+
+// CHECK:   CXXMethodDecl {{.*}} insert 'void (iterator, int *&&)'
+// CHECK:   ParmVarDecl {{.*}} 'iterator'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK:   ParmVarDecl {{.*}} 'int *&&'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+std::vector ints;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition 
implicit_instantiation
+// CHECK:   TemplateArgument type 'int'
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (const int &)'
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (int &&)'
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} insert 'void (iterator, int &&)'
+// CHECK:   ParmVarDecl {{.*}} 'iterator'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr

usx95 wrote:

Done.

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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

https://github.com/usx95 updated 
https://github.com/llvm/llvm-project/pull/117122

>From 9a57223b06a8331a0ef123739a430863dee19d98 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena 
Date: Thu, 21 Nov 2024 07:00:56 +
Subject: [PATCH 1/3] [clang] Infer lifetime_capture_by for STL containers

---
 clang/include/clang/Sema/Sema.h   |  3 +
 clang/lib/Sema/SemaAttr.cpp   | 34 
 clang/lib/Sema/SemaDecl.cpp   |  2 +
 clang/test/Sema/Inputs/lifetime-analysis.h|  5 ++
 .../warn-lifetime-analysis-capture-by.cpp | 79 +++
 5 files changed, 123 insertions(+)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6ea6c67447b6f0..9bafcfec5d4786 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1757,6 +1757,9 @@ class Sema final : public SemaBase {
   /// Add [[clang:::lifetimebound]] attr for std:: functions and methods.
   void inferLifetimeBoundAttribute(FunctionDecl *FD);
 
+  /// Add [[clang:::lifetime_capture(this)]] to STL container methods.
+  void inferLifetimeCaptureByAttribute(FunctionDecl *FD);
+
   /// Add [[gsl::Pointer]] attributes for std:: types.
   void inferGslPointerAttribute(TypedefNameDecl *TD);
 
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 9fbad7ed67ccbe..507f7c40d58782 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+  return RD->hasAttr();
+}
+
+void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
+  if (!FD)
+return;
+  auto *MD = dyn_cast(FD);
+  if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace())
+return;
+  static const llvm::StringSet<> CapturingMethods{"insert", "push",
+  "push_front", "push_back"};
+  if (!CapturingMethods.contains(MD->getName()))
+return;
+  for (ParmVarDecl *PVD : MD->parameters()) {
+if (PVD->hasAttr())
+  return;
+if (IsPointerLikeType(PVD->getType())) {
+  int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
+  PVD->addAttr(
+  LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));
+}
+  }
+}
+
 void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) {
   static const llvm::StringSet<> Nullable{
   "auto_ptr", "shared_ptr", "unique_ptr", "exception_ptr",
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index be570f3a1829d0..5b30d0f2c22d16 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -11913,6 +11913,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, 
FunctionDecl *NewFD,
   NamedDecl *OldDecl = nullptr;
   bool MayNeedOverloadableChecks = false;
 
+  inferLifetimeCaptureByAttribute(NewFD);
   // Merge or overload the declaration with an existing declaration of
   // the same name, if appropriate.
   if (!Previous.empty()) {
@@ -16716,6 +16717,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) 
{
 
   LazyProcessLifetimeCaptureByParams(FD);
   inferLifetimeBoundAttribute(FD);
+  inferLifetimeCaptureByAttribute(FD);
   AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD);
 
   // If C++ exceptions are enabled but we are told extern "C" functions cannot
diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h 
b/clang/test/Sema/Inputs/lifetime-analysis.h
index 41d1e2f074cc83..5c151385b1fe5a 100644
--- a/clang/test/Sema/Inputs/lifetime-analysis.h
+++ b/clang/test/Sema/Inputs/lifetime-analysis.h
@@ -49,6 +49,11 @@ struct vector {
vector(InputIterator first, InputIterator __last);
 
   T &at(int n);
+
+  void push_back(const T&);
+  void push_back(T&&);
+  
+  void insert(iterator, T&&);
 };
 
 template
diff --git a/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp 
b/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
index b3fde386b8616c..462cb2d3f3fd6e 100644
--- a/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
@@ -366,3 +366,82 @@ void use() {
   capture3(std::string(), x3); // expected-warning {{object whose reference is 
captured by 'x3' will be destroyed at the end of the full-expression}}
 }
 } // namespace temporary_views
+
+// 
+// Inferring annotation for STL containers
+// 
+namespace inferred_capture_by {
+const std::string* getLifetimeBoundPointer(const std::string &s 
[[clang::lifetimebound]

[clang] [clang] Infer lifetime_capture_by for STL containers (PR #117122)

2024-11-22 Thread Gábor Horváth via cfe-commits


@@ -7,3 +7,106 @@ struct S {
 };
 
 // CHECK: CXXMethodDecl {{.*}}clang::lifetime_capture_by(a, b, global)
+
+// 
+// Infer annotation for STL container methods.
+// 
+namespace __gnu_cxx {
+template 
+struct basic_iterator {};
+}
+
+namespace std {
+template class allocator {};
+template >
+struct vector {
+  typedef __gnu_cxx::basic_iterator iterator;
+  iterator begin();
+
+  vector();
+
+  void push_back(const T&);
+  void push_back(T&&);
+
+  void insert(iterator, T&&);
+};
+} // namespace std
+struct [[gsl::Pointer()]] View {};
+std::vector views;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition 
implicit_instantiation
+// CHECK:   TemplateArgument type 'View'
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (const View &)'
+// CHECK:   ParmVarDecl {{.*}} 'const View &'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (View &&)'
+// CHECK:   ParmVarDecl {{.*}} 'View &&'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+
+// CHECK:   CXXMethodDecl {{.*}} insert 'void (iterator, View &&)'
+// CHECK:   ParmVarDecl {{.*}} 'iterator'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK:   ParmVarDecl {{.*}} 'View &&'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+template  struct [[gsl::Pointer()]] ViewTemplate {};
+std::vector> templated_views;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition 
implicit_instantiation
+// CHECK:   TemplateArgument type 'ViewTemplate'
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (const ViewTemplate 
&)'
+// CHECK:   ParmVarDecl {{.*}} 'const ViewTemplate &'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (ViewTemplate &&)'
+// CHECK:   ParmVarDecl {{.*}} 'ViewTemplate &&'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+
+// CHECK:   CXXMethodDecl {{.*}} insert 'void (iterator, ViewTemplate 
&&)'
+// CHECK:   ParmVarDecl {{.*}} 'iterator'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK:   ParmVarDecl {{.*}} 'ViewTemplate &&'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+std::vector pointers;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition 
implicit_instantiation
+// CHECK:   TemplateArgument type 'int *'
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (int *const &)'
+// CHECK:   ParmVarDecl {{.*}} 'int *const &'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (int *&&)'
+// CHECK:   ParmVarDecl {{.*}} 'int *&&'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+
+// CHECK:   CXXMethodDecl {{.*}} insert 'void (iterator, int *&&)'
+// CHECK:   ParmVarDecl {{.*}} 'iterator'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK:   ParmVarDecl {{.*}} 'int *&&'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+std::vector ints;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition 
implicit_instantiation
+// CHECK:   TemplateArgument type 'int'
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (const int &)'
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} push_back 'void (int &&)'
+// CHECK-NOT:   LifetimeCaptureByAttr
+
+// CHECK:   CXXMethodDecl {{.*}} insert 'void (iterator, int &&)'
+// CHECK:   ParmVarDecl {{.*}} 'iterator'
+// CHECK:   LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NOT:   LifetimeCaptureByAttr

Xazax-hun wrote:

 Nit: missing new line

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

2024-11-22 Thread Gábor Horváth via cfe-commits

https://github.com/Xazax-hun edited 
https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

2024-11-22 Thread Gábor Horváth via cfe-commits

https://github.com/Xazax-hun approved this pull request.

Once @hokein's comments are addressed, it looks good to me. 

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();

usx95 wrote:

> Should we do the same thing for the one in CheckExprLifetime.cpp?
Makes a lot of sense. Let me do this separately in parallel though.

That said, your example still doesn't work show the warning with the lines 
removed:
```cpp
   if (auto *CTSD = dyn_cast(RD))
 RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
```

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();

hokein wrote:

Thanks for the example. I think I understand what’s happening here.

The primary template Span is annotated with the gsl::Pointer attribute, so all 
its specializations should inherit this attribute.

However, in this example, at the point where we infer the `lifetime_capture_by` 
attribute for `vector`'s method, we don’t yet have a fully completed 
`ClassTemplateSpecializationDecl` for `Span` (and therefore, no 
`PointerAttr`). This is likely because the instantiation of `Span` isn’t 
required for the statement `std::vector> spans;`.

I think the following case would work without this special handling.
```
void use() {
  Span abc({}); // trigger an instantiation of `Span`.
  std::vector> spans;
  spans.push_back(std::vector{1, 2, 3}); // warning.
}
```

I don’t have a better suggestion for addressing this issue directly. However, I 
think we should have a comment explaining it. (Should we do the same thing for 
the one in `CheckExprLifetime.cpp`?)


https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -7,3 +7,106 @@ struct S {
 };
 
 // CHECK: CXXMethodDecl {{.*}}clang::lifetime_capture_by(a, b, global)
+
+// 
+// Infer annotation for STL container methods.
+// 
+namespace __gnu_cxx {
+template 
+struct basic_iterator {};
+}
+
+namespace std {
+template class allocator {};
+template >
+struct vector {
+  typedef __gnu_cxx::basic_iterator iterator;
+  iterator begin();
+
+  vector();
+
+  void push_back(const T&);
+  void push_back(T&&);
+
+  void insert(iterator, T&&);
+};
+} // namespace std
+struct [[gsl::Pointer()]] View {};
+std::vector views;
+// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition 
implicit_instantiation
+// CHECK:   TemplateArgument type 'View'
+// CHECK-NOT:   LifetimeCaptureByAttr

hokein wrote:

Is the `LifetimeCaptureByAttr` attached to the primary template 
`push_back(const T&)`?

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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

https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();

usx95 wrote:

Maybe a better fix would be to propagate this change to the template 
specialization in clang.

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();

usx95 wrote:

We fail to detect pointer types which are templates:
```cpp
template  struct [[gsl::Pointer()]] ViewTemplate {};
std::vector> templated_views;
```

```cpp
template
struct [[gsl::Pointer]] Span {
  Span(const std::vector &V);
};

void use() {
  std::vector> spans;
  spans.push_back(std::vector{1, 2, 3}); // warning.
}
```


https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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

https://github.com/usx95 updated 
https://github.com/llvm/llvm-project/pull/117122

>From 9a57223b06a8331a0ef123739a430863dee19d98 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena 
Date: Thu, 21 Nov 2024 07:00:56 +
Subject: [PATCH 1/2] [clang] Infer lifetime_capture_by for STL containers

---
 clang/include/clang/Sema/Sema.h   |  3 +
 clang/lib/Sema/SemaAttr.cpp   | 34 
 clang/lib/Sema/SemaDecl.cpp   |  2 +
 clang/test/Sema/Inputs/lifetime-analysis.h|  5 ++
 .../warn-lifetime-analysis-capture-by.cpp | 79 +++
 5 files changed, 123 insertions(+)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6ea6c67447b6f0..9bafcfec5d4786 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1757,6 +1757,9 @@ class Sema final : public SemaBase {
   /// Add [[clang:::lifetimebound]] attr for std:: functions and methods.
   void inferLifetimeBoundAttribute(FunctionDecl *FD);
 
+  /// Add [[clang:::lifetime_capture(this)]] to STL container methods.
+  void inferLifetimeCaptureByAttribute(FunctionDecl *FD);
+
   /// Add [[gsl::Pointer]] attributes for std:: types.
   void inferGslPointerAttribute(TypedefNameDecl *TD);
 
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 9fbad7ed67ccbe..507f7c40d58782 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+  return RD->hasAttr();
+}
+
+void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
+  if (!FD)
+return;
+  auto *MD = dyn_cast(FD);
+  if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace())
+return;
+  static const llvm::StringSet<> CapturingMethods{"insert", "push",
+  "push_front", "push_back"};
+  if (!CapturingMethods.contains(MD->getName()))
+return;
+  for (ParmVarDecl *PVD : MD->parameters()) {
+if (PVD->hasAttr())
+  return;
+if (IsPointerLikeType(PVD->getType())) {
+  int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
+  PVD->addAttr(
+  LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));
+}
+  }
+}
+
 void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) {
   static const llvm::StringSet<> Nullable{
   "auto_ptr", "shared_ptr", "unique_ptr", "exception_ptr",
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index be570f3a1829d0..5b30d0f2c22d16 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -11913,6 +11913,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, 
FunctionDecl *NewFD,
   NamedDecl *OldDecl = nullptr;
   bool MayNeedOverloadableChecks = false;
 
+  inferLifetimeCaptureByAttribute(NewFD);
   // Merge or overload the declaration with an existing declaration of
   // the same name, if appropriate.
   if (!Previous.empty()) {
@@ -16716,6 +16717,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) 
{
 
   LazyProcessLifetimeCaptureByParams(FD);
   inferLifetimeBoundAttribute(FD);
+  inferLifetimeCaptureByAttribute(FD);
   AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD);
 
   // If C++ exceptions are enabled but we are told extern "C" functions cannot
diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h 
b/clang/test/Sema/Inputs/lifetime-analysis.h
index 41d1e2f074cc83..5c151385b1fe5a 100644
--- a/clang/test/Sema/Inputs/lifetime-analysis.h
+++ b/clang/test/Sema/Inputs/lifetime-analysis.h
@@ -49,6 +49,11 @@ struct vector {
vector(InputIterator first, InputIterator __last);
 
   T &at(int n);
+
+  void push_back(const T&);
+  void push_back(T&&);
+  
+  void insert(iterator, T&&);
 };
 
 template
diff --git a/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp 
b/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
index b3fde386b8616c..462cb2d3f3fd6e 100644
--- a/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
@@ -366,3 +366,82 @@ void use() {
   capture3(std::string(), x3); // expected-warning {{object whose reference is 
captured by 'x3' will be destroyed at the end of the full-expression}}
 }
 } // namespace temporary_views
+
+// 
+// Inferring annotation for STL containers
+// 
+namespace inferred_capture_by {
+const std::string* getLifetimeBoundPointer(const std::string &s 
[[clang::lifetimebound]

[clang] [clang] Infer lifetime_capture_by for STL containers (PR #117122)

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


@@ -366,3 +366,82 @@ void use() {
   capture3(std::string(), x3); // expected-warning {{object whose reference is 
captured by 'x3' will be destroyed at the end of the full-expression}}
 }
 } // namespace temporary_views
+
+// 
+// Inferring annotation for STL containers
+// 

usx95 wrote:

Done.

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {

usx95 wrote:

Done.

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -1757,6 +1757,9 @@ class Sema final : public SemaBase {
   /// Add [[clang:::lifetimebound]] attr for std:: functions and methods.
   void inferLifetimeBoundAttribute(FunctionDecl *FD);
 
+  /// Add [[clang:::lifetime_capture(this)]] to STL container methods.

usx95 wrote:

Done.

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+  return RD->hasAttr();
+}
+
+void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
+  if (!FD)
+return;
+  auto *MD = dyn_cast(FD);
+  if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace())
+return;
+  static const llvm::StringSet<> CapturingMethods{"insert", "push",
+  "push_front", "push_back"};
+  if (!CapturingMethods.contains(MD->getName()))
+return;
+  for (ParmVarDecl *PVD : MD->parameters()) {
+if (PVD->hasAttr())
+  return;

usx95 wrote:

Yes, this was intentional.

Good catch. Disabled if any of the parameters is explicitly annotated.

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+  return RD->hasAttr();
+}
+
+void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
+  if (!FD)
+return;
+  auto *MD = dyn_cast(FD);
+  if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace())
+return;
+  static const llvm::StringSet<> CapturingMethods{"insert", "push",

usx95 wrote:

SG. Done.

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+  return RD->hasAttr();
+}
+
+void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
+  if (!FD)
+return;
+  auto *MD = dyn_cast(FD);
+  if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace())
+return;
+  static const llvm::StringSet<> CapturingMethods{"insert", "push",

hokein wrote:

I think it is fine to not support it in this patch, worth adding a `FIXME`. 

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();

hokein wrote:

It’s unclear to me why this case needs to be handled separately, and we already 
have one in `CheckExprLifetime.cpp`

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -1757,6 +1757,9 @@ class Sema final : public SemaBase {
   /// Add [[clang:::lifetimebound]] attr for std:: functions and methods.
   void inferLifetimeBoundAttribute(FunctionDecl *FD);
 
+  /// Add [[clang:::lifetime_capture(this)]] to STL container methods.

hokein wrote:

nit: lifetime_capture_by

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -366,3 +366,82 @@ void use() {
   capture3(std::string(), x3); // expected-warning {{object whose reference is 
captured by 'x3' will be destroyed at the end of the full-expression}}
 }
 } // namespace temporary_views
+
+// 
+// Inferring annotation for STL containers
+// 

hokein wrote:

Instead of thoroughly testing diagnostics triggered by the implicitly-added 
`lifetime_capture_by` attribute, I think we can verify the attribute directly 
by inspecting the AST node( see `attr-gsl-owner-pointer.cpp`), and include a 
few small smoke tests here.

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

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


@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {

hokein wrote:

nit: `isPointerLikeType`

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

2024-11-21 Thread Gábor Horváth via cfe-commits


@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+  return RD->hasAttr();
+}
+
+void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
+  if (!FD)
+return;
+  auto *MD = dyn_cast(FD);
+  if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace())
+return;
+  static const llvm::StringSet<> CapturingMethods{"insert", "push",
+  "push_front", "push_back"};
+  if (!CapturingMethods.contains(MD->getName()))
+return;
+  for (ParmVarDecl *PVD : MD->parameters()) {
+if (PVD->hasAttr())
+  return;

Xazax-hun wrote:

Is return intentional here? Do we want an explicit attr to turn off the 
inference for the rest of the params? If that is the case, I think we want to 
turn off the inference for the params before the explicit attr as well, not 
just after. 

https://github.com/llvm/llvm-project/pull/117122
___
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 STL containers (PR #117122)

2024-11-20 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Utkarsh Saxena (usx95)


Changes

This is behind `-Wdangling-capture` warning which is disabled by default.

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


5 Files Affected:

- (modified) clang/include/clang/Sema/Sema.h (+3) 
- (modified) clang/lib/Sema/SemaAttr.cpp (+34) 
- (modified) clang/lib/Sema/SemaDecl.cpp (+2) 
- (modified) clang/test/Sema/Inputs/lifetime-analysis.h (+5) 
- (modified) clang/test/Sema/warn-lifetime-analysis-capture-by.cpp (+79) 


``diff
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6ea6c67447b6f0..9bafcfec5d4786 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1757,6 +1757,9 @@ class Sema final : public SemaBase {
   /// Add [[clang:::lifetimebound]] attr for std:: functions and methods.
   void inferLifetimeBoundAttribute(FunctionDecl *FD);
 
+  /// Add [[clang:::lifetime_capture(this)]] to STL container methods.
+  void inferLifetimeCaptureByAttribute(FunctionDecl *FD);
+
   /// Add [[gsl::Pointer]] attributes for std:: types.
   void inferGslPointerAttribute(TypedefNameDecl *TD);
 
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 9fbad7ed67ccbe..507f7c40d58782 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+  return RD->hasAttr();
+}
+
+void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
+  if (!FD)
+return;
+  auto *MD = dyn_cast(FD);
+  if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace())
+return;
+  static const llvm::StringSet<> CapturingMethods{"insert", "push",
+  "push_front", "push_back"};
+  if (!CapturingMethods.contains(MD->getName()))
+return;
+  for (ParmVarDecl *PVD : MD->parameters()) {
+if (PVD->hasAttr())
+  return;
+if (IsPointerLikeType(PVD->getType())) {
+  int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
+  PVD->addAttr(
+  LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));
+}
+  }
+}
+
 void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) {
   static const llvm::StringSet<> Nullable{
   "auto_ptr", "shared_ptr", "unique_ptr", "exception_ptr",
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index be570f3a1829d0..5b30d0f2c22d16 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -11913,6 +11913,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, 
FunctionDecl *NewFD,
   NamedDecl *OldDecl = nullptr;
   bool MayNeedOverloadableChecks = false;
 
+  inferLifetimeCaptureByAttribute(NewFD);
   // Merge or overload the declaration with an existing declaration of
   // the same name, if appropriate.
   if (!Previous.empty()) {
@@ -16716,6 +16717,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) 
{
 
   LazyProcessLifetimeCaptureByParams(FD);
   inferLifetimeBoundAttribute(FD);
+  inferLifetimeCaptureByAttribute(FD);
   AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD);
 
   // If C++ exceptions are enabled but we are told extern "C" functions cannot
diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h 
b/clang/test/Sema/Inputs/lifetime-analysis.h
index 41d1e2f074cc83..5c151385b1fe5a 100644
--- a/clang/test/Sema/Inputs/lifetime-analysis.h
+++ b/clang/test/Sema/Inputs/lifetime-analysis.h
@@ -49,6 +49,11 @@ struct vector {
vector(InputIterator first, InputIterator __last);
 
   T &at(int n);
+
+  void push_back(const T&);
+  void push_back(T&&);
+  
+  void insert(iterator, T&&);
 };
 
 template
diff --git a/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp 
b/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
index b3fde386b8616c..462cb2d3f3fd6e 100644
--- a/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
@@ -366,3 +366,82 @@ void use() {
   capture3(std::string(), x3); // expected-warning {{object whose reference is 
captured by 'x3' will be destroyed at the end of the full-expression}}
 }
 } // namespace temporary_views
+
+// 
+// Inferring annotation for STL containers
+// 
+namespace inferred_capture_by {
+const std::string* getLifetimeBoundPointer(const std::string &s 
[[clang::lifetimebound]]);
+const std::string* getNotLifetimeBoundPointer(const std::string &s);
+

[clang] [clang] Infer lifetime_capture_by for STL containers (PR #117122)

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

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

This is behind `-Wdangling-capture` warning which is disabled by default.

>From 9a57223b06a8331a0ef123739a430863dee19d98 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena 
Date: Thu, 21 Nov 2024 07:00:56 +
Subject: [PATCH] [clang] Infer lifetime_capture_by for STL containers

---
 clang/include/clang/Sema/Sema.h   |  3 +
 clang/lib/Sema/SemaAttr.cpp   | 34 
 clang/lib/Sema/SemaDecl.cpp   |  2 +
 clang/test/Sema/Inputs/lifetime-analysis.h|  5 ++
 .../warn-lifetime-analysis-capture-by.cpp | 79 +++
 5 files changed, 123 insertions(+)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6ea6c67447b6f0..9bafcfec5d4786 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1757,6 +1757,9 @@ class Sema final : public SemaBase {
   /// Add [[clang:::lifetimebound]] attr for std:: functions and methods.
   void inferLifetimeBoundAttribute(FunctionDecl *FD);
 
+  /// Add [[clang:::lifetime_capture(this)]] to STL container methods.
+  void inferLifetimeCaptureByAttribute(FunctionDecl *FD);
+
   /// Add [[gsl::Pointer]] attributes for std:: types.
   void inferGslPointerAttribute(TypedefNameDecl *TD);
 
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 9fbad7ed67ccbe..507f7c40d58782 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
+static bool IsPointerLikeType(QualType QT) {
+  QT = QT.getNonReferenceType();
+  if (QT->isPointerType())
+return true;
+  auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+return false;
+  RD = RD->getCanonicalDecl();
+  if (auto *CTSD = dyn_cast(RD))
+RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+  return RD->hasAttr();
+}
+
+void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
+  if (!FD)
+return;
+  auto *MD = dyn_cast(FD);
+  if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace())
+return;
+  static const llvm::StringSet<> CapturingMethods{"insert", "push",
+  "push_front", "push_back"};
+  if (!CapturingMethods.contains(MD->getName()))
+return;
+  for (ParmVarDecl *PVD : MD->parameters()) {
+if (PVD->hasAttr())
+  return;
+if (IsPointerLikeType(PVD->getType())) {
+  int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
+  PVD->addAttr(
+  LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));
+}
+  }
+}
+
 void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) {
   static const llvm::StringSet<> Nullable{
   "auto_ptr", "shared_ptr", "unique_ptr", "exception_ptr",
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index be570f3a1829d0..5b30d0f2c22d16 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -11913,6 +11913,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, 
FunctionDecl *NewFD,
   NamedDecl *OldDecl = nullptr;
   bool MayNeedOverloadableChecks = false;
 
+  inferLifetimeCaptureByAttribute(NewFD);
   // Merge or overload the declaration with an existing declaration of
   // the same name, if appropriate.
   if (!Previous.empty()) {
@@ -16716,6 +16717,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) 
{
 
   LazyProcessLifetimeCaptureByParams(FD);
   inferLifetimeBoundAttribute(FD);
+  inferLifetimeCaptureByAttribute(FD);
   AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD);
 
   // If C++ exceptions are enabled but we are told extern "C" functions cannot
diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h 
b/clang/test/Sema/Inputs/lifetime-analysis.h
index 41d1e2f074cc83..5c151385b1fe5a 100644
--- a/clang/test/Sema/Inputs/lifetime-analysis.h
+++ b/clang/test/Sema/Inputs/lifetime-analysis.h
@@ -49,6 +49,11 @@ struct vector {
vector(InputIterator first, InputIterator __last);
 
   T &at(int n);
+
+  void push_back(const T&);
+  void push_back(T&&);
+  
+  void insert(iterator, T&&);
 };
 
 template
diff --git a/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp 
b/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
index b3fde386b8616c..462cb2d3f3fd6e 100644
--- a/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp
@@ -366,3 +366,82 @@ void use() {
   capture3(std::string(), x3); // expected-warning {{object whose reference is 
captured by 'x3' will be destroyed at the end of the full-expression}}
 }
 } // namespace temporary_views
+
+// 
+// Inferring annotation for STL containers
+// 
+namespace inferred_capture_by {
+const std::string