My recent changes to support a 64-bit __platform_wait_t for FreeBSD and
Darwin revealed a problem in std::counting_semaphore. When the default
template argument is used and __platform_wait_t is a 64-bit type, the
numeric_limits<__platform_wait_t>::max() value doesn't fit in ptrdiff_t
and so we get ptrdiff_t(-1), which fails a static_assert in the class
body.
The solution is to cap the value to PTRDIFF_MAX instead of allowing it
to go negative.
libstdc++-v3/ChangeLog:
* include/bits/semaphore_base.h (__platform_semaphore::_S_max):
Limit to PTRDIFF_MAX to avoid negative values.
* testsuite/30_threads/semaphore/least_max_value.cc: New test.
---
While benchmarking the atomic wait/notify changes on freebsd I noticed
that std::counting_semaphore<> no longer compiled.
This didn't show up sooner because until now the only target that
defined __platform_wait_uses_type<__platform_wait_t> == true was linux
where __platform_wait_t is int, and INT_MAX <= PTRDIFF_MAX.
Tested x86_64-linux and x86_64-freebsd14.
libstdc++-v3/include/bits/semaphore_base.h | 14 ++++++++++++--
.../30_threads/semaphore/least_max_value.cc | 9 +++++++++
2 files changed, 21 insertions(+), 2 deletions(-)
create mode 100644
libstdc++-v3/testsuite/30_threads/semaphore/least_max_value.cc
diff --git a/libstdc++-v3/include/bits/semaphore_base.h
b/libstdc++-v3/include/bits/semaphore_base.h
index 82871ce3518b..cb815d340aca 100644
--- a/libstdc++-v3/include/bits/semaphore_base.h
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -173,8 +173,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
using __count_type = __detail::__platform_wait_t;
- static constexpr ptrdiff_t _S_max
- = _Binary ? 1 : __gnu_cxx::__int_traits<__count_type>::__max;
+ static consteval ptrdiff_t
+ _S_calc_max()
+ {
+ if (_Binary)
+ return 1;
+ else if ((ptrdiff_t)__gnu_cxx::__int_traits<__count_type>::__max < 0)
+ return __gnu_cxx::__int_traits<ptrdiff_t>::__max;
+ else
+ return __gnu_cxx::__int_traits<__count_type>::__max;
+ }
+
+ static constexpr ptrdiff_t _S_max = _S_calc_max();
constexpr explicit
__platform_semaphore_impl(__count_type __count) noexcept
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value.cc
b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value.cc
new file mode 100644
index 000000000000..67fa1258b7f0
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value.cc
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++20 } }
+// { dg-require-effective-target gthreads { target { ! *-*-linux* } } }
+// { dg-require-effective-target hosted }
+
+#include <semaphore>
+
+std::counting_semaphore<> sem(0);
+std::counting_semaphore<> sem2(2);
+std::counting_semaphore sem3(3);
--
2.51.1