Skip to content

Commit 280a780

Browse files
committed
[libc++] Drop support for the C++20 Synchronization Library before C++20
When we initially implemented the C++20 synchronization library, we reluctantly accepted for the implementation to be backported to C++03 upon request from the person who provided the patch. This was when we were only starting to have experience with the issues this can create, so we flinched. Nowadays, we have a much stricter stance about not backporting features to previous standards. We have recently started fixing several bugs (and near bugs) in our implementation of the synchronization library. A recurring theme during these reviews has been how difficult to undertand the current code is, and upon inspection it becomes clear that being able to use a few recent C++ features (in particular lambdas) would help a great deal. The code would still be pretty intricate, but it would be a lot easier to reason about the flow of callbacks through things like __thread_poll_with_backoff. As a result, this patch drops support for the synchronization library before C++20. This makes us more strictly conforming and opens the door to major simplifications, in particular around atomic_wait which was supported all the way to C++03. This change will probably have some impact on downstream users, however since the C++20 synchronization library was added only in LLVM 10 (~3 years ago) and it's quite a niche feature, the set of people trying to use this part of the library before C++20 should be reasonably small.
1 parent 90454a6 commit 280a780

File tree

8 files changed

+73
-62
lines changed

8 files changed

+73
-62
lines changed

libcxx/docs/ReleaseNotes/19.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ Deprecations and Removals
6161
the LLVM 19 release while also issuing a deprecation warning). See :ref:`the hardening documentation
6262
<using-hardening-modes>` for more details.
6363

64+
- Support for the C++20 synchronization library (``<barrier>``, ``<latch>``, ``atomic::wait``, etc.) has been
65+
removed in language modes prior to C++20. If you are using these features prior to C++20, you will need to
66+
update to ``-std=c++20``.
67+
6468
- The base template for ``std::char_traits`` has been removed in LLVM 19. If you are using ``std::char_traits`` with
6569
types other than ``char``, ``wchar_t``, ``char8_t``, ``char16_t``, ``char32_t`` or a custom character type for which you
6670
specialized ``std::char_traits``, your code will stop working. The Standard does not mandate that a base template is

libcxx/include/__atomic/atomic.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,8 @@ _LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong_explicit(
429429
return __o->compare_exchange_strong(*__e, __d, __s, __f);
430430
}
431431

432+
#if _LIBCPP_STD_VER >= 20
433+
432434
// atomic_wait
433435

434436
template <class _Tp>
@@ -481,6 +483,8 @@ _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void atomic_notify_all(atomic<_T
481483
__o->notify_all();
482484
}
483485

486+
#endif // _LIBCPP_STD_VER >= 20
487+
484488
// atomic_fetch_add
485489

486490
template <class _Tp>

libcxx/include/__atomic/atomic_base.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ struct __atomic_base // false
102102
return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __m, __m);
103103
}
104104

105+
#if _LIBCPP_STD_VER >= 20
105106
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(_Tp __v, memory_order __m = memory_order_seq_cst) const
106107
volatile _NOEXCEPT {
107108
std::__atomic_wait(*this, __v, __m);
@@ -114,10 +115,8 @@ struct __atomic_base // false
114115
std::__atomic_notify_one(*this);
115116
}
116117
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT { std::__atomic_notify_one(*this); }
117-
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() volatile _NOEXCEPT {
118-
std::__atomic_notify_all(*this);
119-
}
120118
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT { std::__atomic_notify_all(*this); }
119+
#endif // _LIBCPP_STD_VER >= 20
121120

122121
#if _LIBCPP_STD_VER >= 20
123122
_LIBCPP_HIDE_FROM_ABI constexpr __atomic_base() noexcept(is_nothrow_default_constructible_v<_Tp>) : __a_(_Tp()) {}

libcxx/include/__atomic/atomic_flag.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct atomic_flag {
4949
__cxx_atomic_store(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(false), __m);
5050
}
5151

52+
#if _LIBCPP_STD_VER >= 20
5253
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(bool __v, memory_order __m = memory_order_seq_cst) const
5354
volatile _NOEXCEPT {
5455
std::__atomic_wait(*this, _LIBCPP_ATOMIC_FLAG_TYPE(__v), __m);
@@ -65,6 +66,7 @@ struct atomic_flag {
6566
std::__atomic_notify_all(*this);
6667
}
6768
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT { std::__atomic_notify_all(*this); }
69+
#endif
6870

6971
#if _LIBCPP_STD_VER >= 20
7072
_LIBCPP_HIDE_FROM_ABI constexpr atomic_flag() _NOEXCEPT : __a_(false) {}
@@ -141,6 +143,7 @@ inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_clear_explicit(atomic_flag* __o, m
141143
__o->clear(__m);
142144
}
143145

146+
#if _LIBCPP_STD_VER >= 20
144147
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void
145148
atomic_flag_wait(const volatile atomic_flag* __o, bool __v) _NOEXCEPT {
146149
__o->wait(__v);
@@ -178,6 +181,7 @@ atomic_flag_notify_all(volatile atomic_flag* __o) _NOEXCEPT {
178181
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void atomic_flag_notify_all(atomic_flag* __o) _NOEXCEPT {
179182
__o->notify_all();
180183
}
184+
#endif // _LIBCPP_STD_VER >= 20
181185

182186
_LIBCPP_END_NAMESPACE_STD
183187

libcxx/include/atomic

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,12 @@ struct atomic
101101
bool compare_exchange_strong(T& expc, T desr,
102102
memory_order m = memory_order_seq_cst) noexcept;
103103
104-
void wait(T, memory_order = memory_order::seq_cst) const volatile noexcept;
105-
void wait(T, memory_order = memory_order::seq_cst) const noexcept;
106-
void notify_one() volatile noexcept;
107-
void notify_one() noexcept;
108-
void notify_all() volatile noexcept;
109-
void notify_all() noexcept;
104+
void wait(T, memory_order = memory_order::seq_cst) const volatile noexcept; // since C++20
105+
void wait(T, memory_order = memory_order::seq_cst) const noexcept; // since C++20
106+
void notify_one() volatile noexcept; // since C++20
107+
void notify_one() noexcept; // since C++20
108+
void notify_all() volatile noexcept; // since C++20
109+
void notify_all() noexcept; // since C++20
110110
};
111111
112112
template <>
@@ -184,12 +184,12 @@ struct atomic<integral>
184184
integral operator^=(integral op) volatile noexcept;
185185
integral operator^=(integral op) noexcept;
186186
187-
void wait(integral, memory_order = memory_order::seq_cst) const volatile noexcept;
188-
void wait(integral, memory_order = memory_order::seq_cst) const noexcept;
189-
void notify_one() volatile noexcept;
190-
void notify_one() noexcept;
191-
void notify_all() volatile noexcept;
192-
void notify_all() noexcept;
187+
void wait(integral, memory_order = memory_order::seq_cst) const volatile noexcept; // since C++20
188+
void wait(integral, memory_order = memory_order::seq_cst) const noexcept; // since C++20
189+
void notify_one() volatile noexcept; // since C++20
190+
void notify_one() noexcept; // since C++20
191+
void notify_all() volatile noexcept; // since C++20
192+
void notify_all() noexcept; // since C++20
193193
};
194194
195195
template <class T>
@@ -254,12 +254,12 @@ struct atomic<T*>
254254
T* operator-=(ptrdiff_t op) volatile noexcept;
255255
T* operator-=(ptrdiff_t op) noexcept;
256256
257-
void wait(T*, memory_order = memory_order::seq_cst) const volatile noexcept;
258-
void wait(T*, memory_order = memory_order::seq_cst) const noexcept;
259-
void notify_one() volatile noexcept;
260-
void notify_one() noexcept;
261-
void notify_all() volatile noexcept;
262-
void notify_all() noexcept;
257+
void wait(T*, memory_order = memory_order::seq_cst) const volatile noexcept; // since C++20
258+
void wait(T*, memory_order = memory_order::seq_cst) const noexcept; // since C++20
259+
void notify_one() volatile noexcept; // since C++20
260+
void notify_one() noexcept; // since C++20
261+
void notify_all() volatile noexcept; // since C++20
262+
void notify_all() noexcept; // since C++20
263263
};
264264
265265
template<>
@@ -321,12 +321,12 @@ struct atomic<floating-point-type> { // since C++20
321321
floating-point-type operator-=(floating-point-type) volatile noexcept;
322322
floating-point-type operator-=(floating-point-type) noexcept;
323323
324-
void wait(floating-point-type, memory_order = memory_order::seq_cst) const volatile noexcept;
325-
void wait(floating-point-type, memory_order = memory_order::seq_cst) const noexcept;
326-
void notify_one() volatile noexcept;
327-
void notify_one() noexcept;
328-
void notify_all() volatile noexcept;
329-
void notify_all() noexcept;
324+
void wait(floating-point-type, memory_order = memory_order::seq_cst) const volatile noexcept; // since C++20
325+
void wait(floating-point-type, memory_order = memory_order::seq_cst) const noexcept; // since C++20
326+
void notify_one() volatile noexcept; // since C++20
327+
void notify_one() noexcept; // since C++20
328+
void notify_all() volatile noexcept; // since C++20
329+
void notify_all() noexcept; // since C++20
330330
};
331331
332332
// [atomics.nonmembers], non-member functions
@@ -443,23 +443,23 @@ template<class T>
443443
memory_order) noexcept;
444444
445445
template<class T>
446-
void atomic_wait(const volatile atomic<T>*, atomic<T>::value_type) noexcept;
446+
void atomic_wait(const volatile atomic<T>*, atomic<T>::value_type) noexcept; // since C++20
447447
template<class T>
448-
void atomic_wait(const atomic<T>*, atomic<T>::value_type) noexcept;
448+
void atomic_wait(const atomic<T>*, atomic<T>::value_type) noexcept; // since C++20
449449
template<class T>
450-
void atomic_wait_explicit(const volatile atomic<T>*, atomic<T>::value_type,
450+
void atomic_wait_explicit(const volatile atomic<T>*, atomic<T>::value_type, // since C++20
451451
memory_order) noexcept;
452452
template<class T>
453-
void atomic_wait_explicit(const atomic<T>*, atomic<T>::value_type,
453+
void atomic_wait_explicit(const atomic<T>*, atomic<T>::value_type, // since C++20
454454
memory_order) noexcept;
455455
template<class T>
456-
void atomic_notify_one(volatile atomic<T>*) noexcept;
456+
void atomic_notify_one(volatile atomic<T>*) noexcept; // since C++20
457457
template<class T>
458-
void atomic_notify_one(atomic<T>*) noexcept;
458+
void atomic_notify_one(atomic<T>*) noexcept; // since C++20
459459
template<class T>
460-
void atomic_notify_all(volatile atomic<T>*) noexcept;
460+
void atomic_notify_all(volatile atomic<T>*) noexcept; // since C++20
461461
template<class T>
462-
void atomic_notify_all(atomic<T>*) noexcept;
462+
void atomic_notify_all(atomic<T>*) noexcept; // since C++20
463463
464464
// Atomics for standard typedef types
465465
@@ -534,12 +534,12 @@ typedef struct atomic_flag
534534
void clear(memory_order m = memory_order_seq_cst) volatile noexcept;
535535
void clear(memory_order m = memory_order_seq_cst) noexcept;
536536
537-
void wait(bool, memory_order = memory_order::seq_cst) const volatile noexcept;
538-
void wait(bool, memory_order = memory_order::seq_cst) const noexcept;
539-
void notify_one() volatile noexcept;
540-
void notify_one() noexcept;
541-
void notify_all() volatile noexcept;
542-
void notify_all() noexcept;
537+
void wait(bool, memory_order = memory_order::seq_cst) const volatile noexcept; // since C++20
538+
void wait(bool, memory_order = memory_order::seq_cst) const noexcept; // since C++20
539+
void notify_one() volatile noexcept; // since C++20
540+
void notify_one() noexcept; // since C++20
541+
void notify_all() volatile noexcept; // since C++20
542+
void notify_all() noexcept; // since C++20
543543
} atomic_flag;
544544
545545
bool atomic_flag_test(volatile atomic_flag* obj) noexcept;
@@ -557,14 +557,14 @@ void atomic_flag_clear(atomic_flag* obj) noexcept;
557557
void atomic_flag_clear_explicit(volatile atomic_flag* obj, memory_order m) noexcept;
558558
void atomic_flag_clear_explicit(atomic_flag* obj, memory_order m) noexcept;
559559
560-
void atomic_wait(const volatile atomic_flag* obj, T old) noexcept;
561-
void atomic_wait(const atomic_flag* obj, T old) noexcept;
562-
void atomic_wait_explicit(const volatile atomic_flag* obj, T old, memory_order m) noexcept;
563-
void atomic_wait_explicit(const atomic_flag* obj, T old, memory_order m) noexcept;
564-
void atomic_one(volatile atomic_flag* obj) noexcept;
565-
void atomic_one(atomic_flag* obj) noexcept;
566-
void atomic_all(volatile atomic_flag* obj) noexcept;
567-
void atomic_all(atomic_flag* obj) noexcept;
560+
void atomic_wait(const volatile atomic_flag* obj, T old) noexcept; // since C++20
561+
void atomic_wait(const atomic_flag* obj, T old) noexcept; // since C++20
562+
void atomic_wait_explicit(const volatile atomic_flag* obj, T old, memory_order m) noexcept; // since C++20
563+
void atomic_wait_explicit(const atomic_flag* obj, T old, memory_order m) noexcept; // since C++20
564+
void atomic_one(volatile atomic_flag* obj) noexcept; // since C++20
565+
void atomic_one(atomic_flag* obj) noexcept; // since C++20
566+
void atomic_all(volatile atomic_flag* obj) noexcept; // since C++20
567+
void atomic_all(atomic_flag* obj) noexcept; // since C++20
568568
569569
// fences
570570

libcxx/include/barrier

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace std
1717
{
1818
1919
template<class CompletionFunction = see below>
20-
class barrier
20+
class barrier // since C++20
2121
{
2222
public:
2323
using arrival_token = see below;
@@ -71,7 +71,7 @@ namespace std
7171
_LIBCPP_PUSH_MACROS
7272
#include <__undef_macros>
7373

74-
#if _LIBCPP_STD_VER >= 14
74+
#if _LIBCPP_STD_VER >= 20
7575

7676
_LIBCPP_BEGIN_NAMESPACE_STD
7777

@@ -293,7 +293,7 @@ public:
293293

294294
_LIBCPP_END_NAMESPACE_STD
295295

296-
#endif // _LIBCPP_STD_VER >= 14
296+
#endif // _LIBCPP_STD_VER >= 20
297297

298298
_LIBCPP_POP_MACROS
299299

@@ -306,4 +306,4 @@ _LIBCPP_POP_MACROS
306306
# include <variant>
307307
#endif
308308

309-
#endif //_LIBCPP_BARRIER
309+
#endif // _LIBCPP_BARRIER

libcxx/include/latch

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
namespace std
1717
{
1818
19-
class latch
19+
class latch // since C++20
2020
{
2121
public:
2222
static constexpr ptrdiff_t max() noexcept;
@@ -62,7 +62,7 @@ namespace std
6262
_LIBCPP_PUSH_MACROS
6363
#include <__undef_macros>
6464

65-
#if _LIBCPP_STD_VER >= 14
65+
#if _LIBCPP_STD_VER >= 20
6666

6767
_LIBCPP_BEGIN_NAMESPACE_STD
6868

@@ -119,12 +119,12 @@ private:
119119

120120
_LIBCPP_END_NAMESPACE_STD
121121

122-
#endif // _LIBCPP_STD_VER >= 14
122+
#endif // _LIBCPP_STD_VER >= 20
123123

124124
_LIBCPP_POP_MACROS
125125

126126
#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
127127
# include <atomic>
128128
#endif
129129

130-
#endif //_LIBCPP_LATCH
130+
#endif // _LIBCPP_LATCH

libcxx/include/semaphore

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
namespace std {
1717
1818
template<ptrdiff_t least_max_value = implementation-defined>
19-
class counting_semaphore
19+
class counting_semaphore // since C++20
2020
{
2121
public:
2222
static constexpr ptrdiff_t max() noexcept;
@@ -39,7 +39,7 @@ private:
3939
ptrdiff_t counter; // exposition only
4040
};
4141
42-
using binary_semaphore = counting_semaphore<1>;
42+
using binary_semaphore = counting_semaphore<1>; // since C++20
4343
4444
}
4545
@@ -71,7 +71,7 @@ using binary_semaphore = counting_semaphore<1>;
7171
_LIBCPP_PUSH_MACROS
7272
#include <__undef_macros>
7373

74-
#if _LIBCPP_STD_VER >= 14
74+
#if _LIBCPP_STD_VER >= 20
7575

7676
_LIBCPP_BEGIN_NAMESPACE_STD
7777

@@ -176,12 +176,12 @@ using binary_semaphore = counting_semaphore<1>;
176176

177177
_LIBCPP_END_NAMESPACE_STD
178178

179-
#endif // _LIBCPP_STD_VER >= 14
179+
#endif // _LIBCPP_STD_VER >= 20
180180

181181
_LIBCPP_POP_MACROS
182182

183183
#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
184184
# include <atomic>
185185
#endif
186186

187-
#endif //_LIBCPP_SEMAPHORE
187+
#endif // _LIBCPP_SEMAPHORE

0 commit comments

Comments
 (0)