[clang] [LifetimeSafety] Suppress suggestion/inference for moved loans (PR #193899)

Utkarsh Saxena via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 23 23:05:54 PDT 2026


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

>From 4d4a7535dbc913ddcc84cb65e4d449df88b230e6 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Fri, 24 Apr 2026 06:01:33 +0000
Subject: [PATCH 1/2] shared_ptr_false_positive

---
 clang/lib/Analysis/LifetimeSafety/Checker.cpp   |  4 ++++
 clang/test/Sema/Inputs/lifetime-analysis.h      | 17 +++++++++++++++++
 .../Sema/warn-lifetime-safety-suggestions.cpp   | 17 +++++++++++++++++
 3 files changed, 38 insertions(+)

diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index fe103739dbcb0..745e393dc2899 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -143,6 +143,10 @@ class LifetimeChecker {
           AnnotationWarningsMap.try_emplace(MD, ReturnEsc->getReturnExpr());
     };
     for (LoanID LID : EscapedLoans) {
+      // We do not have enough confidence to suggest annotation if the escaping
+      // storage is also moved, e.g. a shared_ptr constructed from a unique_ptr.
+      if (MovedLoans.getMovedLoans(OEF).lookup(LID))
+        continue;
       const Loan *L = FactMgr.getLoanMgr().getLoan(LID);
       const AccessPath &AP = L->getAccessPath();
       if (const auto *PVD = AP.getAsPlaceholderParam())
diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h b/clang/test/Sema/Inputs/lifetime-analysis.h
index 9806cce15d8f5..9cc7c79b0eb36 100644
--- a/clang/test/Sema/Inputs/lifetime-analysis.h
+++ b/clang/test/Sema/Inputs/lifetime-analysis.h
@@ -211,6 +211,23 @@ unique_ptr<T> make_unique(Args&&... args) {
   return unique_ptr<T>(new T(args...));
 }
 
+template<typename T>
+struct shared_ptr {
+  shared_ptr();
+  explicit shared_ptr(T*);
+  shared_ptr(const shared_ptr<T>&);
+  shared_ptr(shared_ptr<T>&&);
+  
+  template<typename U>
+  shared_ptr(unique_ptr<U>&& up) : ptr_(up.get()) { up.release(); }
+
+  ~shared_ptr();
+  T &operator*();
+  T *operator->();
+  T *get() const;
+  T* ptr_;
+};
+
 template<typename T>
 struct optional {
   optional();
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 08405c4607f3c..9996e728991ee 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -570,3 +570,20 @@ void test_inference() {
   (void)ptr; // expected-note {{later used here}}
 }
 } // namespace make_unique_suggestion
+
+namespace GH193747 {
+
+std::unique_ptr<int> create_up();
+std::shared_ptr<int> create_sp() {
+  return create_up();
+}
+
+struct S {
+  int* field;
+  S(std::unique_ptr<int>&& up) : field(up.get()) { up.release(); }
+};
+
+S foo() {
+  return S(create_up());
+}
+} // namespace GH193747

>From 4ef7a2f259a53119ed2a9902fd37c30d56ab611c Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Fri, 24 Apr 2026 06:05:38 +0000
Subject: [PATCH 2/2] fix docs

---
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 745e393dc2899..c918bf2306a3a 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -143,8 +143,8 @@ class LifetimeChecker {
           AnnotationWarningsMap.try_emplace(MD, ReturnEsc->getReturnExpr());
     };
     for (LoanID LID : EscapedLoans) {
-      // We do not have enough confidence to suggest annotation if the escaping
-      // storage is also moved, e.g. a shared_ptr constructed from a unique_ptr.
+      // Skip annotation suggestion for moved loans, as ownership transfer
+      // obscures the lifetime relationship (e.g., shared_ptr from unique_ptr).
       if (MovedLoans.getMovedLoans(OEF).lookup(LID))
         continue;
       const Loan *L = FactMgr.getLoanMgr().getLoan(LID);



More information about the cfe-commits mailing list