[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