https://github.com/Prabhuk updated 
https://github.com/llvm/llvm-project/pull/157171

>From e6af544156940a1041a01a44d73dae76ac322111 Mon Sep 17 00:00:00 2001
From: prabhukr <prabh...@google.com>
Date: Fri, 5 Sep 2025 13:35:10 -0700
Subject: [PATCH 1/3] [clang][ThreadSafety] Handle mutex scope

Before emitting warning about locks being held at the end of function
scope check if the underlying mutex is function scoped or not.
---
 clang/lib/Analysis/ThreadSafety.cpp              | 16 ++++++++++++++++
 .../clang/thread/thread.mutex/lock.verify.cpp    |  6 ++++++
 2 files changed, 22 insertions(+)

diff --git a/clang/lib/Analysis/ThreadSafety.cpp 
b/clang/lib/Analysis/ThreadSafety.cpp
index 131170df9976e..b215a6e6d74cc 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -2443,6 +2443,22 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet 
&EntrySet,
       if (join(FactMan[*EntryIt], ExitFact, JoinLoc, EntryLEK))
         *EntryIt = Fact;
     } else if (!ExitFact.managed() || EntryLEK == LEK_LockedAtEndOfFunction) {
+      if (EntryLEK == LEK_LockedAtEndOfFunction) {
+        const til::SExpr *Sexp = ExitFact.sexpr();
+        const VarDecl *Var = nullptr;
+
+        if (const auto *Proj = dyn_cast<til::Project>(Sexp)) {
+          if (const auto *Base = dyn_cast<til::LiteralPtr>(Proj->record()))
+            Var = dyn_cast_or_null<VarDecl>(Base->clangDecl());
+        } else if (const auto *LP = dyn_cast<til::LiteralPtr>(Sexp)) {
+          Var = dyn_cast_or_null<VarDecl>(LP->clangDecl());
+        }
+
+        if (Var && Var->getStorageDuration() == SD_Automatic &&
+            Var->getDeclContext() == CurrentFunction) {
+          continue;
+        }
+      }
       ExitFact.handleRemovalFromIntersection(ExitSet, FactMan, JoinLoc,
                                              EntryLEK, Handler);
     }
diff --git a/libcxx/test/extensions/clang/thread/thread.mutex/lock.verify.cpp 
b/libcxx/test/extensions/clang/thread/thread.mutex/lock.verify.cpp
index 51ffa6962ac83..e0d4ec39ea845 100644
--- a/libcxx/test/extensions/clang/thread/thread.mutex/lock.verify.cpp
+++ b/libcxx/test/extensions/clang/thread/thread.mutex/lock.verify.cpp
@@ -45,3 +45,9 @@ void f3() {
      expected-warning {{mutex 'm2' is still held at the end of function}} \
      expected-warning {{mutex 'm3' is still held at the end of function}}
 #endif
+
+void f4() {
+  std::mutex local_m0;
+  std::mutex local_m1;
+  std::lock(local_m0, local_m1);
+}

>From e9e92e57859901a8247fad62656d1fd68cd6fa53 Mon Sep 17 00:00:00 2001
From: prabhukr <prabh...@google.com>
Date: Fri, 5 Sep 2025 13:48:07 -0700
Subject: [PATCH 2/3] Use better variable name.

---
 clang/lib/Analysis/ThreadSafety.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Analysis/ThreadSafety.cpp 
b/clang/lib/Analysis/ThreadSafety.cpp
index b215a6e6d74cc..56055f1ee6e3e 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -2445,17 +2445,17 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet 
&EntrySet,
     } else if (!ExitFact.managed() || EntryLEK == LEK_LockedAtEndOfFunction) {
       if (EntryLEK == LEK_LockedAtEndOfFunction) {
         const til::SExpr *Sexp = ExitFact.sexpr();
-        const VarDecl *Var = nullptr;
+        const VarDecl *MutexVar = nullptr;
 
         if (const auto *Proj = dyn_cast<til::Project>(Sexp)) {
           if (const auto *Base = dyn_cast<til::LiteralPtr>(Proj->record()))
-            Var = dyn_cast_or_null<VarDecl>(Base->clangDecl());
+            MutexVar = dyn_cast_or_null<VarDecl>(Base->clangDecl());
         } else if (const auto *LP = dyn_cast<til::LiteralPtr>(Sexp)) {
-          Var = dyn_cast_or_null<VarDecl>(LP->clangDecl());
+          MutexVar = dyn_cast_or_null<VarDecl>(LP->clangDecl());
         }
 
-        if (Var && Var->getStorageDuration() == SD_Automatic &&
-            Var->getDeclContext() == CurrentFunction) {
+        if (MutexVar && MutexVar->getStorageDuration() == SD_Automatic &&
+            MutexVar->getDeclContext() == CurrentFunction) {
           continue;
         }
       }

>From a7e28b9317a8539d31e251fcef76c5d97d36a29d Mon Sep 17 00:00:00 2001
From: prabhukr <prabh...@google.com>
Date: Fri, 5 Sep 2025 14:06:36 -0700
Subject: [PATCH 3/3] Add regression tests.

---
 clang/test/PCH/thread-safety-attrs.cpp | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/clang/test/PCH/thread-safety-attrs.cpp 
b/clang/test/PCH/thread-safety-attrs.cpp
index d33917e518597..67fb87ea16d54 100644
--- a/clang/test/PCH/thread-safety-attrs.cpp
+++ b/clang/test/PCH/thread-safety-attrs.cpp
@@ -316,4 +316,21 @@ void sls_fun_bad_12() {
     expected-warning{{releasing mutex 'sls_mu' that was not held}}
 }
 
+
+template <class T, class... Ts>
+void LockMutexes(T &m, Ts &...ms) __attribute__((exclusive_lock_function(m, 
ms...)));
+
+Mutex m0, m1;
+void non_local_mutex_held() {
+  LockMutexes(m0, m1); // expected-note {{mutex acquired here}} \
+  // expected-note {{mutex acquired here}}
+} // expected-warning{{mutex 'm0' is still held at the end of function}} \
+// expected-warning{{mutex 'm1' is still held at the end of function}}
+
+void no_local_mutex_held_warning() {
+  Mutex local_m0;
+  Mutex local_m1;
+  LockMutexes(local_m0, local_m1);
+} // No warnings expected at end of function scope as the mutexes are function 
local.
+
 #endif

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

Reply via email to