[libc++] Add the thread safety annotations unconditionally (#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.
This commit is contained in:
Nikolas Klauser
2025-07-05 18:07:07 +02:00
committed by GitHub
parent c9d9c3e349
commit 22f8ceded4
15 changed files with 138 additions and 124 deletions

View File

@@ -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',
@@ -41,9 +44,13 @@ 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_THREAD_SAFETY_ANNOTATION',
'_LIBCPP_TRY_ACQUIRE_CAPABILITY',
'_LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY',
'_LIBCPP_USING_IF_EXISTS',
'_LIBCPP_WEAK',
]

View File

@@ -114,11 +114,6 @@ enable or disable extended libc++ behavior.
ensure that the appropriate experimental library (usually ``libc++experimental.a``)
is linked into their program.
**_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS**:
This macro is used to enable -Wthread-safety annotations on libc++'s
``std::mutex`` and ``std::lock_guard``. By default, these annotations are
disabled and must be manually enabled by the user.
**_LIBCPP_HARDENING_MODE**:
This macro is used to choose the :ref:`hardening mode <using-hardening-modes>`.

View File

@@ -903,23 +903,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__)
@@ -1147,6 +1130,60 @@ typedef __char32_t char32_t;
# define _LIBCPP_PREFERRED_NAME(x)
# endif
# if __has_cpp_attribute(_Clang::__scoped_lockable__)
# define _LIBCPP_SCOPED_LOCKABLE [[_Clang::__scoped_lockable__]]
# else
# define _LIBCPP_SCOPED_LOCKABLE
# endif
# if __has_cpp_attribute(_Clang::__capability__)
# define _LIBCPP_CAPABILITY(...) [[_Clang::__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_cpp_attribute(_Clang::__try_acquire_capability__)
# define _LIBCPP_TRY_ACQUIRE_CAPABILITY(...) [[_Clang::__try_acquire_capability__(__VA_ARGS__)]]
# else
# define _LIBCPP_TRY_ACQUIRE_CAPABILITY(...)
# endif
# if __has_cpp_attribute(_Clang::__acquire_shared_capability__)
# define _LIBCPP_ACQUIRE_SHARED_CAPABILITY [[_Clang::__acquire_shared_capability__]]
# else
# define _LIBCPP_ACQUIRE_SHARED_CAPABILITY
# endif
# if __has_cpp_attribute(_Clang::__try_acquire_shared_capability__)
# define _LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(...) [[_Clang::__try_acquire_shared_capability__(__VA_ARGS__)]]
# else
# define _LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(...)
# endif
# if __has_cpp_attribute(_Clang::__release_capability__)
# define _LIBCPP_RELEASE_CAPABILITY [[_Clang::__release_capability__]]
# else
# define _LIBCPP_RELEASE_CAPABILITY
# endif
# if __has_cpp_attribute(_Clang::__release_shared_capability__)
# define _LIBCPP_RELEASE_SHARED_CAPABILITY [[_Clang::__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 defined(_LIBCPP_ABI_MICROSOFT) && __has_declspec_attribute(empty_bases)
# define _LIBCPP_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
# else

View File

@@ -19,7 +19,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Mutex>
class _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) lock_guard {
class _LIBCPP_SCOPED_LOCKABLE lock_guard {
public:
typedef _Mutex mutex_type;
@@ -27,16 +27,14 @@ private:
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_RELEASE_CAPABILITY _LIBCPP_HIDE_FROM_ABI ~lock_guard() { __m_.unlock(); }
lock_guard(lock_guard const&) = delete;
lock_guard& operator=(lock_guard const&) = delete;

View File

@@ -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 @@ public:
~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());
_LIBCPP_ACQUIRE_CAPABILITY() void lock();
_LIBCPP_TRY_ACQUIRE_CAPABILITY(true) bool try_lock() _NOEXCEPT;
_LIBCPP_RELEASE_CAPABILITY void unlock() _NOEXCEPT;
typedef __libcpp_mutex_t* native_handle_type;
_LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; }

View File

@@ -434,7 +434,7 @@ public:
};
template <class _Mutex>
class _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) scoped_lock<_Mutex> {
class _LIBCPP_SCOPED_LOCKABLE scoped_lock<_Mutex> {
public:
typedef _Mutex mutex_type;
@@ -442,16 +442,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;

View File

@@ -183,7 +183,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:
@@ -194,35 +194,23 @@ 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_ACQUIRE_CAPABILITY() _LIBCPP_HIDE_FROM_ABI void lock() { return __base_.lock(); }
_LIBCPP_TRY_ACQUIRE_CAPABILITY(true) _LIBCPP_HIDE_FROM_ABI bool try_lock() { return __base_.try_lock(); }
_LIBCPP_RELEASE_CAPABILITY _LIBCPP_HIDE_FROM_ABI void unlock() { 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_ACQUIRE_SHARED_CAPABILITY _LIBCPP_HIDE_FROM_ABI void lock_shared() { return __base_.lock_shared(); }
_LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(true) _LIBCPP_HIDE_FROM_ABI bool try_lock_shared() {
return __base_.try_lock_shared();
}
_LIBCPP_HIDE_FROM_ABI void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__()) {
return __base_.unlock_shared();
}
_LIBCPP_RELEASE_SHARED_CAPABILITY _LIBCPP_HIDE_FROM_ABI void unlock_shared() { return __base_.unlock_shared(); }
// typedef __shared_mutex_base::native_handle_type native_handle_type;
// _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return __base::unlock_shared(); }
};
# 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:
@@ -233,17 +221,17 @@ 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();
_LIBCPP_TRY_ACQUIRE_CAPABILITY(true) bool try_lock();
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) _LIBCPP_HIDE_FROM_ABI bool
try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time) {
return try_lock_until(chrono::steady_clock::now() + __rel_time);
}
template <class _Clock, class _Duration>
_LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
_LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)) {
_LIBCPP_TRY_ACQUIRE_CAPABILITY(true) _LIBCPP_HIDE_FROM_ABI bool
try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time) {
unique_lock<mutex> __lk(__base_.__mut_);
if (__base_.__state_ & __base_.__write_entered_) {
while (true) {
@@ -270,20 +258,20 @@ public:
return true;
}
void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_capability__());
_LIBCPP_RELEASE_CAPABILITY void unlock();
// 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));
_LIBCPP_ACQUIRE_SHARED_CAPABILITY void lock_shared();
_LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(true) bool try_lock_shared();
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) _LIBCPP_HIDE_FROM_ABI bool
try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time) {
return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
}
template <class _Clock, class _Duration>
_LIBCPP_HIDE_FROM_ABI bool try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
_LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)) {
_LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(true) _LIBCPP_HIDE_FROM_ABI bool
try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time) {
unique_lock<mutex> __lk(__base_.__mut_);
if ((__base_.__state_ & __base_.__write_entered_) ||
(__base_.__state_ & __base_.__n_readers_) == __base_.__n_readers_) {
@@ -302,7 +290,7 @@ public:
return true;
}
void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__());
_LIBCPP_RELEASE_SHARED_CAPABILITY void unlock_shared();
};
template <class _Mutex>

View File

@@ -11,9 +11,8 @@
// <mutex>
// This test does not define _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS so it
// should compile without any warnings or errors even though this pattern is not
// understood by the thread safety annotations.
// This test does not set -Wthread-safety so it should compile without any warnings or errors even though this pattern
// is not understood by the thread safety annotations.
#include <mutex>

View File

@@ -6,16 +6,16 @@
//
//===----------------------------------------------------------------------===//
// On Windows Clang bugs out when both __declspec and __attribute__ are present,
// the processing goes awry preventing the definition of the types.
// XFAIL: msvc
// UNSUPPORTED: no-threads
// REQUIRES: thread-safety
// <mutex>
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
// GCC doesn't have thread safety attributes
// UNSUPPORTED: gcc
// ADDITIONAL_COMPILE_FLAGS: -Wthread-safety
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
#include <mutex>

View File

@@ -6,16 +6,16 @@
//
//===----------------------------------------------------------------------===//
// On Windows Clang bugs out when both __declspec and __attribute__ are present,
// the processing goes awry preventing the definition of the types.
// XFAIL: msvc
// UNSUPPORTED: no-threads
// REQUIRES: thread-safety
// <mutex>
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
// GCC doesn't have thread safety attributes
// UNSUPPORTED: gcc
// ADDITIONAL_COMPILE_FLAGS: -Wthread-safety
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
#include <mutex>

View File

@@ -6,21 +6,19 @@
//
//===----------------------------------------------------------------------===//
// On Windows Clang bugs out when both __declspec and __attribute__ are present,
// the processing goes awry preventing the definition of the types.
// XFAIL: msvc
// UNSUPPORTED: no-threads
// REQUIRES: thread-safety
// <mutex>
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
// GCC doesn't have thread safety attributes
// UNSUPPORTED: gcc
// ADDITIONAL_COMPILE_FLAGS: -Wthread-safety
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
#include <mutex>
std::mutex m;
void f() {
m.lock();
} // expected-error {{mutex 'm' is still held at the end of function}}
void f() { m.lock(); } // expected-warning {{mutex 'm' is still held at the end of function}}

View File

@@ -6,16 +6,16 @@
//
//===----------------------------------------------------------------------===//
// On Windows Clang bugs out when both __declspec and __attribute__ are present,
// the processing goes awry preventing the definition of the types.
// XFAIL: msvc
// UNSUPPORTED: no-threads
// REQUIRES: thread-safety
// <mutex>
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
// GCC doesn't have thread safety attributes
// UNSUPPORTED: gcc
// ADDITIONAL_COMPILE_FLAGS: -Wthread-safety
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
#include <mutex>

View File

@@ -8,12 +8,11 @@
// UNSUPPORTED: c++03, c++11, c++14
// UNSUPPORTED: no-threads
// REQUIRES: thread-safety
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
// On Windows Clang bugs out when both __declspec and __attribute__ are present,
// the processing goes awry preventing the definition of the types.
// XFAIL: msvc
// GCC doesn't have thread safety attributes
// UNSUPPORTED: gcc
// ADDITIONAL_COMPILE_FLAGS: -Wthread-safety
// <shared_mutex>
//
@@ -51,13 +50,13 @@ void f() {
{
m.lock_shared();
read(data); // ok
++data; // expected-error {{writing variable 'data' requires holding shared_mutex 'm' exclusively}}
++data; // expected-warning {{writing variable 'data' requires holding shared_mutex 'm' exclusively}}
m.unlock_shared();
}
{
if (m.try_lock_shared()) {
read(data); // ok
++data; // expected-error {{writing variable 'data' requires holding shared_mutex 'm' exclusively}}
++data; // expected-warning {{writing variable 'data' requires holding shared_mutex 'm' exclusively}}
m.unlock_shared();
}
}

View File

@@ -8,12 +8,11 @@
// UNSUPPORTED: c++03, c++11
// UNSUPPORTED: no-threads
// REQUIRES: thread-safety
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
// On Windows Clang bugs out when both __declspec and __attribute__ are present,
// the processing goes awry preventing the definition of the types.
// XFAIL: msvc
// GCC doesn't have thread safety attributes
// UNSUPPORTED: gcc
// ADDITIONAL_COMPILE_FLAGS: -Wthread-safety
// <shared_mutex>
//
@@ -68,27 +67,27 @@ void f(std::chrono::time_point<std::chrono::steady_clock> tp, std::chrono::milli
{
m.lock_shared();
read(data); // ok
++data; // expected-error {{writing variable 'data' requires holding shared_timed_mutex 'm' exclusively}}
++data; // expected-warning {{writing variable 'data' requires holding shared_timed_mutex 'm' exclusively}}
m.unlock_shared();
}
{
if (m.try_lock_shared()) {
read(data); // ok
++data; // expected-error {{writing variable 'data' requires holding shared_timed_mutex 'm' exclusively}}
++data; // expected-warning {{writing variable 'data' requires holding shared_timed_mutex 'm' exclusively}}
m.unlock_shared();
}
}
{
if (m.try_lock_shared_for(d)) {
read(data); // ok
++data; // expected-error {{writing variable 'data' requires holding shared_timed_mutex 'm' exclusively}}
++data; // expected-warning {{writing variable 'data' requires holding shared_timed_mutex 'm' exclusively}}
m.unlock_shared();
}
}
{
if (m.try_lock_shared_until(tp)) {
read(data); // ok
++data; // expected-error {{writing variable 'data' requires holding shared_timed_mutex 'm' exclusively}}
++data; // expected-warning {{writing variable 'data' requires holding shared_timed_mutex 'm' exclusively}}
m.unlock_shared();
}
}

View File

@@ -134,11 +134,6 @@ DEFAULT_FEATURES = [
Feature(name=lambda cfg: "msvc-{}".format(*_msvcVersion(cfg)), when=_isMSVC),
Feature(name=lambda cfg: "msvc-{}.{}".format(*_msvcVersion(cfg)), when=_isMSVC),
Feature(
name="thread-safety",
when=lambda cfg: hasCompileFlag(cfg, "-Werror=thread-safety"),
actions=[AddCompileFlag("-Werror=thread-safety")],
),
Feature(
name="diagnose-if-support",
when=lambda cfg: hasCompileFlag(cfg, "-Wuser-defined-warnings"),