[libcxx-commits] [libcxx] [libc++][ThreadSafety] Add thread safety annotations for variadic std::scoped_lock (PR #204462)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jun 18 12:47:19 PDT 2026


================
@@ -469,25 +469,44 @@ public:
 };
 
 template <class... _MArgs>
+#      if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 2101
+class _LIBCPP_SCOPED_LOCKABLE scoped_lock {
+#      else
 class scoped_lock {
+#      endif
   static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required");
   typedef tuple<_MArgs&...> _MutexTuple;
 
 public:
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(_MArgs&... __margs) : __t_(__margs...) {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(_MArgs&... __margs)
+#      if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 2101
+      _LIBCPP_ACQUIRE_CAPABILITY(__margs...)
+#      endif
+      : __t_(__margs...) {
     std::lock(__margs...);
   }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI scoped_lock(adopt_lock_t, _MArgs&... __margs) : __t_(__margs...) {}
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI scoped_lock(adopt_lock_t, _MArgs&... __margs)
+#      if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 2101
+      _LIBCPP_REQUIRES_CAPABILITY(__margs...)
+#      endif
+      : __t_(__margs...) {
+  }
 
-  _LIBCPP_HIDE_FROM_ABI ~scoped_lock() { __unlock_unpack(make_index_sequence<sizeof...(_MArgs)>(), __t_); }
+#      if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 2101
+  _LIBCPP_RELEASE_CAPABILITY
+#      endif
+  _LIBCPP_HIDE_FROM_ABI ~scoped_lock() {
+    __unlock_unpack(make_index_sequence<sizeof...(_MArgs)>(), __t_);
+  }
 
   scoped_lock(scoped_lock const&)            = delete;
   scoped_lock& operator=(scoped_lock const&) = delete;
 
 private:
   template <size_t... _Indx>
-  _LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(index_sequence<_Indx...>, _MutexTuple& __mt) {
+  _LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_HIDE_FROM_ABI static void
----------------
AnthonyCalandraGeotab wrote:

Just annotating with `_LIBCPP_RELEASE_CAPABILITY` by itself gives me the following error:

> error: 'clang::release_capability' attribute without capability arguments can only be applied to non-static methods of a class

OK, fair enough I guess... there's probably some limitation I'm not aware of here.
So now let me try passing it the mutexes through the tuple.

When I look at how the macro is defined I see:

```cpp
#define _LIBCPP_RELEASE_CAPABILITY [[_Clang::__release_capability__]]
```

So looks like it doesn't take arguments. I thought that's kind of confusing because the error messages makes me think it could. I'll make them take arguments then:

```cpp
#define _LIBCPP_RELEASE_CAPABILITY(...) [[_Clang::__release_capability__(__VA_ARGS__)]]
```

I think the next error I got was the attribute was being applied to the function type (I had to put it after the parameter list to access the arguments in the macro).

So let's use a GNU-style attribute... Okay, works now. :)

https://github.com/llvm/llvm-project/pull/204462


More information about the libcxx-commits mailing list