From d4046ae6df51ad41370dfe474bfb3c93fd8e166d Mon Sep 17 00:00:00 2001 From: Aaron Puchert Date: Sun, 3 Aug 2025 19:50:17 +0200 Subject: [PATCH] Thread safety analysis: Don't warn on acquiring reentrant capability (#150857) The point of reentrant capabilities is that they can be acquired multiple times, so they should probably be excluded from requiring a negative capability on acquisition via -Wthread-safety-negative. However, we still propagate explicit negative requirements. (cherry picked from commit a048aeb06e5de571eadd646860c320b9a67d1efc) --- clang/lib/Analysis/ThreadSafety.cpp | 2 +- .../SemaCXX/warn-thread-safety-negative.cpp | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp index 80e7c8eff671a..dadb0b757a2c8 100644 --- a/clang/lib/Analysis/ThreadSafety.cpp +++ b/clang/lib/Analysis/ThreadSafety.cpp @@ -1331,7 +1331,7 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, FSet.removeLock(FactMan, NegC); } else { - if (inCurrentScope(*Entry) && !Entry->asserted()) + if (inCurrentScope(*Entry) && !Entry->asserted() && !Entry->reentrant()) Handler.handleNegativeNotHeld(Entry->getKind(), Entry->toString(), NegC.toString(), Entry->loc()); } diff --git a/clang/test/SemaCXX/warn-thread-safety-negative.cpp b/clang/test/SemaCXX/warn-thread-safety-negative.cpp index 9eabd67e4fc76..0caf6d6139e58 100644 --- a/clang/test/SemaCXX/warn-thread-safety-negative.cpp +++ b/clang/test/SemaCXX/warn-thread-safety-negative.cpp @@ -21,6 +21,15 @@ class LOCKABLE Mutex { void AssertReaderHeld() ASSERT_SHARED_LOCK(); }; +class LOCKABLE REENTRANT_CAPABILITY ReentrantMutex { +public: + void Lock() EXCLUSIVE_LOCK_FUNCTION(); + void Unlock() UNLOCK_FUNCTION(); + + // for negative capabilities + const ReentrantMutex& operator!() const { return *this; } +}; + class SCOPED_LOCKABLE MutexLock { public: MutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu); @@ -89,6 +98,29 @@ class Foo { } }; +class Reentrant { + ReentrantMutex mu; + +public: + void acquire() { + mu.Lock(); // no warning -- reentrant mutex + mu.Unlock(); + } + + void requireNegative() EXCLUSIVE_LOCKS_REQUIRED(!mu) { // warning? + mu.Lock(); + mu.Unlock(); + } + + void callRequireNegative() { + requireNegative(); // expected-warning{{calling function 'requireNegative' requires negative capability '!mu'}} + } + + void callHaveNegative() EXCLUSIVE_LOCKS_REQUIRED(!mu) { + requireNegative(); + } +}; + } // end namespace SimpleTest Mutex globalMutex;