[libcxx-commits] [libcxx] [libc++] Add the thread safety annotations unconditionally (PR #117497)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Sun Nov 24 08:32:21 PST 2024


https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/117497

For these annotations to do anything you need `-Wthread-safety`, in which case users most likely enable them anyways. This avoids that users have to explictly define a macro just to use the feature they already had to opt-in to.


>From e666b3cc327148b9c0757cfdeee0fc4569863b3e Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sun, 24 Nov 2024 16:44:16 +0100
Subject: [PATCH] [libc++] Add the thread safety annotations unconditionally

---
 libcxx/.clang-format                |  9 +++-
 libcxx/include/__config             | 71 ++++++++++++++++++++++-------
 libcxx/include/__mutex/lock_guard.h | 10 ++--
 libcxx/include/__mutex/mutex.h      |  8 ++--
 libcxx/include/mutex                | 11 ++---
 libcxx/include/shared_mutex         | 53 +++++++++------------
 6 files changed, 96 insertions(+), 66 deletions(-)

diff --git a/libcxx/.clang-format b/libcxx/.clang-format
index f548119652c19a..b4b9ee01350de2 100644
--- a/libcxx/.clang-format
+++ b/libcxx/.clang-format
@@ -16,8 +16,11 @@ AllowShortLambdasOnASingleLine: All
 AttributeMacros: [
                   '_ALIGNAS_TYPE',
                   '_ALIGNAS',
+                  '_LIBCPP_ACQUIRE_CAPABILITY',
+                  '_LIBCPP_ACQUIRE_SHARED_CAPABILITY',
                   '_LIBCPP_ALIGNOF',
                   '_LIBCPP_ALWAYS_INLINE',
+                  '_LIBCPP_CAPABILITY',
                   '_LIBCPP_CONSTEXPR_SINCE_CXX14',
                   '_LIBCPP_CONSTEXPR_SINCE_CXX17',
                   '_LIBCPP_CONSTEXPR_SINCE_CXX20',
@@ -43,10 +46,14 @@ AttributeMacros: [
                   '_LIBCPP_NO_UNIQUE_ADDRESS',
                   '_LIBCPP_NOALIAS',
                   '_LIBCPP_OVERRIDABLE_FUNC_VIS',
+                  '_LIBCPP_RELEASE_CAPABILITY',
+                  '_LIBCPP_REQUIRES_CAPABILITY',
+                  '_LIBCPP_SCOPED_LOCKABLE',
                   '_LIBCPP_STANDALONE_DEBUG',
                   '_LIBCPP_TEMPLATE_DATA_VIS',
                   '_LIBCPP_TEMPLATE_VIS',
-                  '_LIBCPP_THREAD_SAFETY_ANNOTATION',
+                  '_LIBCPP_TRY_ACQUIRE_CAPABILITY',
+                  '_LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY',
                   '_LIBCPP_USING_IF_EXISTS',
                   '_LIBCPP_WEAK',
                  ]
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 9db00cd0c9fb93..badc7764c9e1d0 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -933,23 +933,6 @@ typedef __char32_t char32_t;
 #    define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
 #  endif
 
-// Work around the attribute handling in clang.  When both __declspec and
-// __attribute__ are present, the processing goes awry preventing the definition
-// of the types. In MinGW mode, __declspec evaluates to __attribute__, and thus
-// combining the two does work.
-#  if defined(_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS) && defined(__clang__) &&                                       \
-      __has_attribute(acquire_capability) && !defined(_MSC_VER)
-#    define _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS 1
-#  else
-#    define _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS 0
-#  endif
-
-#  if _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS
-#    define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) __attribute__((x))
-#  else
-#    define _LIBCPP_THREAD_SAFETY_ANNOTATION(x)
-#  endif
-
 #  if _LIBCPP_STD_VER >= 20
 #    define _LIBCPP_CONSTINIT constinit
 #  elif __has_attribute(__require_constant_initialization__)
@@ -1196,6 +1179,60 @@ typedef __char32_t char32_t;
 #    define _LIBCPP_INIT_PRIORITY_MAX
 #  endif
 
+#  if __has_attribute(__scoped_lockable__)
+#    define _LIBCPP_SCOPED_LOCKABLE __attribute__((__scoped_lockable__))
+#  else
+#    define _LIBCPP_SCOPED_LOCKABLE
+#  endif
+
+#  if __has_attribute(__capability__)
+#    define _LIBCPP_CAPABILITY(...) __attribute((__capability__(__VA_ARGS__)))
+#  else
+#    define _LIBCPP_CAPABILITY(...)
+#  endif
+
+#  if __has_attribute(__acquire_capability__)
+#    define _LIBCPP_ACQUIRE_CAPABILITY(...) __attribute__((__acquire_capability__(__VA_ARGS__)))
+#  else
+#    define _LIBCPP_ACQUIRE_CAPABILITY(...)
+#  endif
+
+#  if __has_attribute(__try_acquire_capability__)
+#    define _LIBCPP_TRY_ACQUIRE_CAPABILITY(...) __attribute__((__try_acquire_capability__(__VA_ARGS__)))
+#  else
+#    define _LIBCPP_TRY_ACQUIRE_CAPABILITY(...)
+#  endif
+
+#  if __has_attribute(__acquire_shared_capability__)
+#    define _LIBCPP_ACQUIRE_SHARED_CAPABILITY(...) __attribute__((__acquire_shared_capability__(__VA_ARGS__)))
+#  else
+#    define _LIBCPP_ACQUIRE_SHARED_CAPABILITY(...)
+#  endif
+
+#  if __has_attribute(__try_acquire_shared_capability__)
+#    define _LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(...) __attribute__((__try_acquire_shared_capability__(__VA_ARGS__)))
+#  else
+#    define _LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(...)
+#  endif
+
+#  if __has_attribute(__release_capability__)
+#    define _LIBCPP_RELEASE_CAPABILITY __attribute__((__release_capability__))
+#  else
+#    define _LIBCPP_RELEASE_CAPABILITY
+#  endif
+
+#  if __has_attribute(__release_shared_capability__)
+#    define _LIBCPP_RELEASE_SHARED_CAPABILITY __attribute__((__release_shared_capability__))
+#  else
+#    define _LIBCPP_RELEASE_SHARED_CAPABILITY
+#  endif
+
+#  if __has_attribute(__requires_capability__)
+#    define _LIBCPP_REQUIRES_CAPABILITY(...) __attribute__((__requires_capability__(__VA_ARGS__)))
+#  else
+#    define _LIBCPP_REQUIRES_CAPABILITY(...)
+#  endif
+
 #  if __has_attribute(__format__)
 // The attribute uses 1-based indices for ordinary and static member functions.
 // The attribute uses 2-based indices for non-static member functions.
diff --git a/libcxx/include/__mutex/lock_guard.h b/libcxx/include/__mutex/lock_guard.h
index 50765cdd0475e7..4b1ecc5fd03904 100644
--- a/libcxx/include/__mutex/lock_guard.h
+++ b/libcxx/include/__mutex/lock_guard.h
@@ -19,7 +19,7 @@
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Mutex>
-class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) lock_guard {
+class _LIBCPP_TEMPLATE_VIS _LIBCPP_SCOPED_LOCKABLE lock_guard {
 public:
   typedef _Mutex mutex_type;
 
@@ -27,16 +27,14 @@ class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) loc
   mutex_type& __m_;
 
 public:
-  [[__nodiscard__]]
-  _LIBCPP_HIDE_FROM_ABI explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI explicit lock_guard(mutex_type& __m) _LIBCPP_ACQUIRE_CAPABILITY(__m)
       : __m_(__m) {
     __m_.lock();
   }
 
-  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI lock_guard(mutex_type& __m, adopt_lock_t)
-      _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_REQUIRES_CAPABILITY(__m)
       : __m_(__m) {}
-  _LIBCPP_HIDE_FROM_ABI ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) { __m_.unlock(); }
+  _LIBCPP_HIDE_FROM_ABI ~lock_guard() _LIBCPP_RELEASE_CAPABILITY { __m_.unlock(); }
 
   lock_guard(lock_guard const&)            = delete;
   lock_guard& operator=(lock_guard const&) = delete;
diff --git a/libcxx/include/__mutex/mutex.h b/libcxx/include/__mutex/mutex.h
index 317320287902f5..d36cba082db278 100644
--- a/libcxx/include/__mutex/mutex.h
+++ b/libcxx/include/__mutex/mutex.h
@@ -21,7 +21,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex {
+class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CAPABILITY("mutex") mutex {
   __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
 
 public:
@@ -36,9 +36,9 @@ class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mut
   ~mutex() _NOEXCEPT;
 #  endif
 
-  void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability());
-  bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
-  void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
+  void lock() _LIBCPP_ACQUIRE_CAPABILITY();
+  bool try_lock() _NOEXCEPT _LIBCPP_TRY_ACQUIRE_CAPABILITY(true);
+  void unlock() _NOEXCEPT _LIBCPP_RELEASE_CAPABILITY;
 
   typedef __libcpp_mutex_t* native_handle_type;
   _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; }
diff --git a/libcxx/include/mutex b/libcxx/include/mutex
index ecbfc5607dcc78..4414ba1dc144c1 100644
--- a/libcxx/include/mutex
+++ b/libcxx/include/mutex
@@ -435,7 +435,7 @@ public:
 };
 
 template <class _Mutex>
-class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) scoped_lock<_Mutex> {
+class _LIBCPP_TEMPLATE_VIS _LIBCPP_SCOPED_LOCKABLE scoped_lock<_Mutex> {
 public:
   typedef _Mutex mutex_type;
 
@@ -443,16 +443,15 @@ private:
   mutex_type& __m_;
 
 public:
-  [[nodiscard]]
-  _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(mutex_type& __m) _LIBCPP_ACQUIRE_CAPABILITY(__m)
       : __m_(__m) {
     __m_.lock();
   }
 
-  ~scoped_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) { __m_.unlock(); }
+  _LIBCPP_RELEASE_CAPABILITY _LIBCPP_HIDE_FROM_ABI ~scoped_lock() { __m_.unlock(); }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t, mutex_type& __m)
-      _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
+  [[nodiscard]]
+  _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t, mutex_type& __m) _LIBCPP_REQUIRES_CAPABILITY(__m)
       : __m_(__m) {}
 
   scoped_lock(scoped_lock const&)            = delete;
diff --git a/libcxx/include/shared_mutex b/libcxx/include/shared_mutex
index 2552119405419c..513eebddc462ac 100644
--- a/libcxx/include/shared_mutex
+++ b/libcxx/include/shared_mutex
@@ -180,7 +180,7 @@ struct _LIBCPP_EXPORTED_FROM_ABI __shared_mutex_base {
 };
 
 #    if _LIBCPP_STD_VER >= 17
-class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_THREAD_SAFETY_ANNOTATION(__capability__("shared_mutex")) shared_mutex {
+class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CAPABILITY("shared_mutex") shared_mutex {
   __shared_mutex_base __base_;
 
 public:
@@ -191,25 +191,16 @@ public:
   shared_mutex& operator=(const shared_mutex&) = delete;
 
   // Exclusive ownership
-  _LIBCPP_HIDE_FROM_ABI void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_capability__()) {
-    return __base_.lock();
-  }
-  _LIBCPP_HIDE_FROM_ABI bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)) {
-    return __base_.try_lock();
-  }
-  _LIBCPP_HIDE_FROM_ABI void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_capability__()) {
-    return __base_.unlock();
-  }
+  _LIBCPP_HIDE_FROM_ABI void lock() _LIBCPP_ACQUIRE_CAPABILITY() { return __base_.lock(); }
+  _LIBCPP_HIDE_FROM_ABI bool try_lock() _LIBCPP_TRY_ACQUIRE_CAPABILITY(true) { return __base_.try_lock(); }
+  _LIBCPP_HIDE_FROM_ABI void unlock() _LIBCPP_RELEASE_CAPABILITY { return __base_.unlock(); }
 
   // Shared ownership
-  _LIBCPP_HIDE_FROM_ABI void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_shared_capability__()) {
-    return __base_.lock_shared();
-  }
-  _LIBCPP_HIDE_FROM_ABI bool try_lock_shared()
-      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)) {
+  _LIBCPP_HIDE_FROM_ABI void lock_shared() _LIBCPP_ACQUIRE_SHARED_CAPABILITY() { return __base_.lock_shared(); }
+  _LIBCPP_HIDE_FROM_ABI bool try_lock_shared() _LIBCPP_ACQUIRE_SHARED_CAPABILITY(true) {
     return __base_.try_lock_shared();
   }
-  _LIBCPP_HIDE_FROM_ABI void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__()) {
+  _LIBCPP_HIDE_FROM_ABI void unlock_shared() _LIBCPP_RELEASE_SHARED_CAPABILITY {
     return __base_.unlock_shared();
   }
 
@@ -218,8 +209,7 @@ public:
 };
 #    endif
 
-class _LIBCPP_EXPORTED_FROM_ABI
-_LIBCPP_THREAD_SAFETY_ANNOTATION(__capability__("shared_timed_mutex")) shared_timed_mutex {
+class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CAPABILITY("shared_timed_mutex") shared_timed_mutex {
   __shared_mutex_base __base_;
 
 public:
@@ -230,32 +220,31 @@ public:
   shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
 
   // Exclusive ownership
-  void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_capability__());
-  bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true));
+  void lock() _LIBCPP_ACQUIRE_CAPABILITY();
+  bool try_lock() _LIBCPP_TRY_ACQUIRE_CAPABILITY(true);
   template <class _Rep, class _Period>
   _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
-      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)) {
+      _LIBCPP_TRY_ACQUIRE_CAPABILITY(true) {
     return try_lock_until(chrono::steady_clock::now() + __rel_time);
   }
+
   template <class _Clock, class _Duration>
-  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
-  try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
-      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true));
-  void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_capability__());
+  _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
+      _LIBCPP_TRY_ACQUIRE_CAPABILITY(true);
+  void unlock() _LIBCPP_RELEASE_CAPABILITY;
 
   // Shared ownership
-  void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_shared_capability__());
-  bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true));
+  void lock_shared() _LIBCPP_ACQUIRE_SHARED_CAPABILITY();
+  bool try_lock_shared() _LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(true);
   template <class _Rep, class _Period>
   _LIBCPP_HIDE_FROM_ABI bool try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
-      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)) {
+      _LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(true) {
     return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
   }
   template <class _Clock, class _Duration>
-  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
-  try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
-      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true));
-  void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__());
+  _LIBCPP_HIDE_FROM_ABI bool try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
+      _LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(true);
+  void unlock_shared() _LIBCPP_RELEASE_SHARED_CAPABILITY;
 };
 
 template <class _Clock, class _Duration>



More information about the libcxx-commits mailing list