aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/parser.cc2
-rw-r--r--gcc/testsuite/g++.dg/template/dependent-base6.C4
-rw-r--r--gcc/tree-vect-slp.cc100
-rw-r--r--gcc/tree-vectorizer.h9
-rw-r--r--libstdc++-v3/include/bits/atomic_base.h2
-rw-r--r--libstdc++-v3/include/bits/chrono.h72
-rw-r--r--libstdc++-v3/include/bits/hashtable.h18
-rw-r--r--libstdc++-v3/include/bits/shared_ptr_atomic.h57
-rw-r--r--libstdc++-v3/include/bits/std_mutex.h26
-rw-r--r--libstdc++-v3/include/bits/stl_map.h20
-rw-r--r--libstdc++-v3/include/bits/stl_multimap.h20
-rw-r--r--libstdc++-v3/include/bits/stl_multiset.h12
-rw-r--r--libstdc++-v3/include/bits/stl_set.h12
-rw-r--r--libstdc++-v3/include/bits/stl_tree.h4
-rw-r--r--libstdc++-v3/include/bits/this_thread_sleep.h20
-rw-r--r--libstdc++-v3/include/bits/unordered_map.h20
-rw-r--r--libstdc++-v3/include/bits/unordered_set.h20
-rw-r--r--libstdc++-v3/include/debug/map.h18
-rw-r--r--libstdc++-v3/include/debug/multimap.h18
-rw-r--r--libstdc++-v3/include/debug/multiset.h10
-rw-r--r--libstdc++-v3/include/debug/set.h10
-rw-r--r--libstdc++-v3/include/debug/unordered_map24
-rw-r--r--libstdc++-v3/include/debug/unordered_set24
-rw-r--r--libstdc++-v3/include/std/condition_variable20
-rw-r--r--libstdc++-v3/include/std/format198
-rw-r--r--libstdc++-v3/include/std/mutex18
-rw-r--r--libstdc++-v3/include/std/shared_mutex39
-rw-r--r--libstdc++-v3/python/libstdcxx/v6/printers.py6
-rw-r--r--libstdc++-v3/src/c++11/thread.cc48
-rw-r--r--libstdc++-v3/src/c++17/fs_path.cc74
-rw-r--r--libstdc++-v3/src/c++20/atomic.cc18
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/atomic/pr118757.cc29
-rw-r--r--libstdc++-v3/testsuite/20_util/weak_ptr/pr118757.cc30
-rw-r--r--libstdc++-v3/testsuite/30_threads/condition_variable/members/116586.cc60
-rw-r--r--libstdc++-v3/testsuite/30_threads/future/members/116586.cc55
-rw-r--r--libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/116586.cc72
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc22
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc24
-rw-r--r--libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/116586.cc97
-rw-r--r--libstdc++-v3/testsuite/30_threads/this_thread/113327.cc29
-rw-r--r--libstdc++-v3/testsuite/30_threads/this_thread/sleep_for.cc13
-rw-r--r--libstdc++-v3/testsuite/30_threads/this_thread/sleep_until.cc26
-rw-r--r--libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/116586.cc57
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/string.cc89
-rw-r--r--libstdc++-v3/testsuite/std/time/month_day/io.cc41
-rw-r--r--libstdc++-v3/testsuite/std/time/month_day_last/io.cc41
-rw-r--r--libstdc++-v3/testsuite/std/time/month_weekday/io.cc41
-rw-r--r--libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc41
-rw-r--r--libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc41
-rw-r--r--libstdc++-v3/testsuite/std/time/weekday_last/io.cc41
-rw-r--r--libstdc++-v3/testsuite/std/time/year_month/io.cc41
51 files changed, 1447 insertions, 386 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 1ed2f37..9280632 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -19091,7 +19091,7 @@ cp_parser_mem_initializer_id (cp_parser* parser)
return cp_parser_class_name (parser,
/*typename_keyword_p=*/true,
/*template_keyword_p=*/template_p,
- typename_type,
+ class_type,
/*check_dependency_p=*/true,
/*class_head_p=*/false,
/*is_declaration=*/true);
diff --git a/gcc/testsuite/g++.dg/template/dependent-base6.C b/gcc/testsuite/g++.dg/template/dependent-base6.C
index b4bc5c2..9f2a7a2 100644
--- a/gcc/testsuite/g++.dg/template/dependent-base6.C
+++ b/gcc/testsuite/g++.dg/template/dependent-base6.C
@@ -8,5 +8,7 @@ struct A {
struct S1 : A::B { }; // OK
-template<class T> struct S2 : T::B { }; // OK, used to fail
+template<class T> struct S2 : T::B { // OK, used to fail
+ S2() : T::B() { } // Also OK
+};
template struct S2<A>;
diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
index fe3bcff..13a2995 100644
--- a/gcc/tree-vect-slp.cc
+++ b/gcc/tree-vect-slp.cc
@@ -53,6 +53,9 @@ along with GCC; see the file COPYING3. If not see
#include "sreal.h"
#include "predict.h"
+#define REDUC_GROUP_FIRST_ELEMENT(S) \
+ (gcc_checking_assert (!(S)->dr_aux.dr), (S)->first_element)
+
static bool vect_transform_slp_perm_load_1 (vec_info *, slp_tree,
load_permutation_t &,
const vec<tree> &,
@@ -4189,14 +4192,50 @@ vect_build_slp_instance (vec_info *vinfo,
static bool
vect_analyze_slp_reduc_chain (loop_vec_info vinfo,
scalar_stmts_to_slp_tree_map_t *bst_map,
- vec<stmt_vec_info> &scalar_stmts,
- stmt_vec_info reduc_phi_info,
+ stmt_vec_info scalar_stmt,
unsigned max_tree_size, unsigned *limit)
{
- /* If there's no budget left bail out early. */
- if (*limit == 0)
+ vec<stmt_vec_info> scalar_stmts = vNULL;
+
+ bool fail = false;
+ /* ??? We could leave operation code checking to SLP discovery. */
+ code_helper code = STMT_VINFO_REDUC_CODE (STMT_VINFO_REDUC_DEF
+ (vect_orig_stmt (scalar_stmt)));
+ bool first = true;
+ stmt_vec_info next_stmt = scalar_stmt;
+ do
+ {
+ stmt_vec_info stmt = next_stmt;
+ gimple_match_op op;
+ if (!gimple_extract_op (STMT_VINFO_STMT (stmt), &op))
+ gcc_unreachable ();
+ tree reduc_def = gimple_arg (STMT_VINFO_STMT (stmt),
+ STMT_VINFO_REDUC_IDX (stmt));
+ next_stmt = vect_stmt_to_vectorize (vinfo->lookup_def (reduc_def));
+ gcc_assert (is_a <gphi *> (STMT_VINFO_STMT (next_stmt))
+ || STMT_VINFO_REDUC_IDX (next_stmt) != -1);
+ if (!gimple_extract_op (STMT_VINFO_STMT (vect_orig_stmt (stmt)), &op))
+ gcc_unreachable ();
+ if (CONVERT_EXPR_CODE_P (op.code)
+ && (first
+ || is_a <gphi *> (STMT_VINFO_STMT (next_stmt))))
+ ;
+ else if (code != op.code)
+ {
+ fail = true;
+ break;
+ }
+ else
+ scalar_stmts.safe_push (stmt);
+ first = false;
+ }
+ while (!is_a <gphi *> (STMT_VINFO_STMT (next_stmt)));
+ if (fail || scalar_stmts.length () <= 1)
return false;
+ scalar_stmts.reverse ();
+ stmt_vec_info reduc_phi_info = next_stmt;
+
/* Build the tree for the SLP instance. */
vec<stmt_vec_info> root_stmt_infos = vNULL;
vec<tree> remain = vNULL;
@@ -4315,7 +4354,9 @@ vect_analyze_slp_reduc_chain (loop_vec_info vinfo,
return true;
}
+
/* Failed to SLP. */
+ scalar_stmts.release ();
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
"SLP discovery of reduction chain failed\n");
@@ -4338,55 +4379,14 @@ vect_analyze_slp_reduction (loop_vec_info vinfo,
if (*limit == 0)
return false;
- vec<stmt_vec_info> scalar_stmts = vNULL;
/* Try to gather a reduction chain. */
if (! force_single_lane
- && STMT_VINFO_DEF_TYPE (scalar_stmt) == vect_reduction_def)
- {
- bool fail = false;
- /* ??? We could leave operation code checking to SLP discovery. */
- code_helper code
- = STMT_VINFO_REDUC_CODE (STMT_VINFO_REDUC_DEF
- (vect_orig_stmt (scalar_stmt)));
- bool first = true;
- stmt_vec_info next_stmt = scalar_stmt;
- do
- {
- stmt_vec_info stmt = next_stmt;
- gimple_match_op op;
- if (!gimple_extract_op (STMT_VINFO_STMT (stmt), &op))
- gcc_unreachable ();
- tree reduc_def = gimple_arg (STMT_VINFO_STMT (stmt),
- STMT_VINFO_REDUC_IDX (stmt));
- next_stmt = vect_stmt_to_vectorize (vinfo->lookup_def (reduc_def));
- gcc_assert (is_a <gphi *> (STMT_VINFO_STMT (next_stmt))
- || STMT_VINFO_REDUC_IDX (next_stmt) != -1);
- if (!gimple_extract_op (STMT_VINFO_STMT (vect_orig_stmt (stmt)), &op))
- gcc_unreachable ();
- if (CONVERT_EXPR_CODE_P (op.code)
- && (first
- || is_a <gphi *> (STMT_VINFO_STMT (next_stmt))))
- ;
- else if (code != op.code)
- {
- fail = true;
- break;
- }
- else
- scalar_stmts.safe_push (stmt);
- first = false;
- }
- while (!is_a <gphi *> (STMT_VINFO_STMT (next_stmt)));
- if (!fail && scalar_stmts.length () > 1)
- {
- scalar_stmts.reverse ();
- if (vect_analyze_slp_reduc_chain (vinfo, bst_map, scalar_stmts,
- next_stmt, max_tree_size, limit))
- return true;
- scalar_stmts.release ();
- }
- }
+ && STMT_VINFO_DEF_TYPE (scalar_stmt) == vect_reduction_def
+ && vect_analyze_slp_reduc_chain (vinfo, bst_map, scalar_stmt,
+ max_tree_size, limit))
+ return true;
+ vec<stmt_vec_info> scalar_stmts;
scalar_stmts.create (1);
scalar_stmts.quick_push (scalar_stmt);
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index a6c313e..4785cbd 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1538,7 +1538,7 @@ public:
/* Whether the stmt is SLPed, loop-based vectorized, or both. */
enum slp_vect_type slp_type;
- /* Interleaving and reduction chains info. */
+ /* Interleaving chains info. */
/* First element in the group. */
stmt_vec_info first_element;
/* Pointer to the next element in the group. */
@@ -1711,13 +1711,6 @@ struct gather_scatter_info {
#define DR_GROUP_GAP(S) \
(gcc_checking_assert ((S)->dr_aux.dr), (S)->gap)
-#define REDUC_GROUP_FIRST_ELEMENT(S) \
- (gcc_checking_assert (!(S)->dr_aux.dr), (S)->first_element)
-#define REDUC_GROUP_NEXT_ELEMENT(S) \
- (gcc_checking_assert (!(S)->dr_aux.dr), (S)->next_element)
-#define REDUC_GROUP_SIZE(S) \
- (gcc_checking_assert (!(S)->dr_aux.dr), (S)->size)
-
#define STMT_VINFO_RELEVANT_P(S) ((S)->relevant != vect_unused_in_scope)
#define PURE_SLP_STMT(S) ((S)->slp_type == pure_slp)
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 0f3f6b1..7e4ad2b 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -1538,7 +1538,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_S_required_aligment()
{
if constexpr (is_floating_point_v<_Vt> || is_pointer_v<_Vt>)
- return alignof(_Vt);
+ return __alignof__(_Vt);
else if constexpr ((sizeof(_Vt) & (sizeof(_Vt) - 1)) || sizeof(_Vt) > 16)
return alignof(_Vt);
else
diff --git a/libstdc++-v3/include/bits/chrono.h b/libstdc++-v3/include/bits/chrono.h
index 8de8e75..7f505aa 100644
--- a/libstdc++-v3/include/bits/chrono.h
+++ b/libstdc++-v3/include/bits/chrono.h
@@ -1515,6 +1515,78 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
} // namespace filesystem
#endif // C++17 && HOSTED
+#if defined _GLIBCXX_USE_NANOSLEEP || defined _GLIBCXX_USE_CLOCK_REALTIME \
+ || defined _GLIBCXX_HAS_GTHREADS
+namespace chrono
+{
+/// @cond undocumented
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
+ // Convert a chrono::duration to a relative time represented as timespec
+ // (e.g. for use with nanosleep).
+ template<typename _Rep, typename _Period>
+ [[__nodiscard__]] _GLIBCXX14_CONSTEXPR inline
+ struct ::timespec
+ __to_timeout_timespec(const duration<_Rep, _Period>& __d)
+ {
+ struct ::timespec __ts{};
+
+ if (__d < __d.zero()) // Negative timeouts don't make sense.
+ return __ts;
+
+ if constexpr (ratio_greater<_Period, ratio<1>>::value
+ || treat_as_floating_point<_Rep>::value)
+ {
+ // Converting from e.g. chrono::hours::max() to chrono::seconds
+ // would evaluate LLONG_MAX * 3600 which would overflow.
+ // Limit to chrono::seconds::max().
+ chrono::duration<double> __fmax(chrono::seconds::max());
+ if (__d > __fmax) [[__unlikely__]]
+ return chrono::__to_timeout_timespec(chrono::seconds::max());
+ }
+
+ auto __s = chrono::duration_cast<chrono::seconds>(__d);
+
+ if constexpr (is_integral<time_t>::value) // POSIX.1-2001 allows floating
+ {
+ // Also limit to time_t maximum (only relevant for 32-bit time_t).
+ constexpr auto __tmax = numeric_limits<time_t>::max();
+ if (__s.count() > __tmax) [[__unlikely__]]
+ {
+ __ts.tv_sec = __tmax;
+ return __ts;
+ }
+ }
+
+ auto __ns = chrono::duration_cast<chrono::nanoseconds>(__d - __s);
+
+ if constexpr (treat_as_floating_point<_Rep>::value)
+ if (__ns.count() > 999999999) [[__unlikely__]]
+ __ns = chrono::nanoseconds(999999999);
+
+ __ts.tv_sec = static_cast<time_t>(__s.count());
+ __ts.tv_nsec = static_cast<long>(__ns.count());
+ return __ts;
+ }
+#pragma GCC diagnostic pop
+
+ // Convert a chrono::time_point to an absolute time represented as timespec.
+ // All times before the epoch get converted to the epoch, so this assumes
+ // that we only use it for clocks where that's true.
+ // It should be safe to use this for system_clock and steady_clock.
+ template<typename _Clock, typename _Dur>
+ [[__nodiscard__]] _GLIBCXX14_CONSTEXPR inline
+ struct ::timespec
+ __to_timeout_timespec(const time_point<_Clock, _Dur>& __t)
+ {
+ return chrono::__to_timeout_timespec(__t.time_since_epoch());
+ }
+
+/// @endcond
+} // namespace chrono
+#endif // USE_NANOSLEEP || USE_CLOCK_REALTIME || HAS_GTHREADS
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index b5a71f5..06cc51a 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -38,7 +38,7 @@
#include <bits/enable_special_members.h>
#include <bits/stl_algobase.h> // fill_n, is_permutation
#include <bits/stl_function.h> // __has_is_transparent_t
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
# include <bits/node_handle.h>
#endif
@@ -349,7 +349,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using size_type = typename __hashtable_base::size_type;
using difference_type = typename __hashtable_base::difference_type;
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
using node_type = _Node_handle<_Key, _Value, __node_alloc_type>;
using insert_return_type = _Node_insert_return<iterator, node_type>;
#endif
@@ -1931,7 +1931,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
-> const_iterator
{ return const_iterator(_M_locate(__k)); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Key, typename _Value, typename _Alloc,
typename _ExtractKey, typename _Equal,
typename _Hash, typename _RangeHash, typename _Unused,
@@ -1979,7 +1979,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
std::size_t __bkt = _M_bucket_index(__code);
return const_iterator(_M_find_node_tr(__bkt, __k, __code));
}
-#endif
+#endif // C++20 __glibcxx_generic_unordered_lookup
template<typename _Key, typename _Value, typename _Alloc,
typename _ExtractKey, typename _Equal,
@@ -2007,7 +2007,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __result;
}
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Key, typename _Value, typename _Alloc,
typename _ExtractKey, typename _Equal,
typename _Hash, typename _RangeHash, typename _Unused,
@@ -2052,7 +2052,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __result;
}
-#endif
+#endif // C++20 __glibcxx_generic_unordered_lookup
template<typename _Key, typename _Value, typename _Alloc,
typename _ExtractKey, typename _Equal,
@@ -2102,7 +2102,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return { __beg, __ite };
}
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Key, typename _Value, typename _Alloc,
typename _ExtractKey, typename _Equal,
typename _Hash, typename _RangeHash, typename _Unused,
@@ -2190,7 +2190,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return { __beg, __ite };
}
-#endif
+#endif // C++20 __glibcxx_generic_unordered_lookup
// Find the node before the one whose key compares equal to k in the bucket
// bkt. Return nullptr if no node is found.
@@ -2966,7 +2966,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
#pragma GCC diagnostic pop
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
template<typename, typename, typename> class _Hash_merge_helper { };
#endif // C++17
diff --git a/libstdc++-v3/include/bits/shared_ptr_atomic.h b/libstdc++-v3/include/bits/shared_ptr_atomic.h
index cc7841a..cbc4bf6 100644
--- a/libstdc++-v3/include/bits/shared_ptr_atomic.h
+++ b/libstdc++-v3/include/bits/shared_ptr_atomic.h
@@ -392,6 +392,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
class _Sp_atomic
{
using value_type = _Tp;
+ using element_type = typename _Tp::element_type;
friend struct atomic<_Tp>;
@@ -420,7 +421,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
~_Atomic_count()
{
- auto __val = _M_val.load(memory_order_relaxed);
+ auto __val = _AtomicRef(_M_val).load(memory_order_relaxed);
_GLIBCXX_TSAN_MUTEX_DESTROY(&_M_val);
__glibcxx_assert(!(__val & _S_lock_bit));
if (auto __pi = reinterpret_cast<pointer>(__val))
@@ -442,18 +443,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
// To acquire the lock we flip the LSB from 0 to 1.
- auto __current = _M_val.load(memory_order_relaxed);
+ _AtomicRef __aref(_M_val);
+ auto __current = __aref.load(memory_order_relaxed);
while (__current & _S_lock_bit)
{
#if __glibcxx_atomic_wait
__detail::__thread_relax();
#endif
- __current = _M_val.load(memory_order_relaxed);
+ __current = __aref.load(memory_order_relaxed);
}
_GLIBCXX_TSAN_MUTEX_TRY_LOCK(&_M_val);
- while (!_M_val.compare_exchange_strong(__current,
+ while (!__aref.compare_exchange_strong(__current,
__current | _S_lock_bit,
__o,
memory_order_relaxed))
@@ -474,7 +476,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
unlock(memory_order __o) const noexcept
{
_GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
- _M_val.fetch_sub(1, __o);
+ _AtomicRef(_M_val).fetch_sub(1, __o);
_GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
}
@@ -487,7 +489,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__o = memory_order_release;
auto __x = reinterpret_cast<uintptr_t>(__c._M_pi);
_GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
- __x = _M_val.exchange(__x, __o);
+ __x = _AtomicRef(_M_val).exchange(__x, __o);
_GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
__c._M_pi = reinterpret_cast<pointer>(__x & ~_S_lock_bit);
}
@@ -495,19 +497,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __glibcxx_atomic_wait
// Precondition: caller holds lock!
void
- _M_wait_unlock(memory_order __o) const noexcept
+ _M_wait_unlock(const element_type* const& __ptr, memory_order __o) const noexcept
{
+ auto __old_ptr = __ptr;
_GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
- auto __v = _M_val.fetch_sub(1, memory_order_relaxed);
+ uintptr_t __old_pi
+ = _AtomicRef(_M_val).fetch_sub(1, memory_order_relaxed) - 1u;
_GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
- _M_val.wait(__v & ~_S_lock_bit, __o);
+
+ // Ensure that the correct value of _M_ptr is visible after locking,
+ // by upgrading relaxed or consume to acquire.
+ auto __lo = __o;
+ if (__o != memory_order_seq_cst)
+ __lo = memory_order_acquire;
+
+ std::__atomic_wait_address(
+ &_M_val,
+ [=, &__ptr, this](uintptr_t __new_pi)
+ {
+ if (__old_pi != (__new_pi & ~_S_lock_bit))
+ // control block changed, we can wake up
+ return true;
+
+ // control block is same, we need to check if ptr changed,
+ // the lock needs to be taken first, the value of pi may have
+ // also been updated in meantime, so reload it
+ __new_pi = reinterpret_cast<uintptr_t>(this->lock(__lo));
+ auto __new_ptr = __ptr;
+ this->unlock(memory_order_relaxed);
+ // wake up if either of the values changed
+ return __new_pi != __old_pi || __new_ptr != __old_ptr;
+ },
+ [__o, this] { return _AtomicRef(_M_val).load(__o); });
}
void
notify_one() noexcept
{
_GLIBCXX_TSAN_MUTEX_PRE_SIGNAL(&_M_val);
- _M_val.notify_one();
+ _AtomicRef(_M_val).notify_one();
_GLIBCXX_TSAN_MUTEX_POST_SIGNAL(&_M_val);
}
@@ -515,17 +543,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
notify_all() noexcept
{
_GLIBCXX_TSAN_MUTEX_PRE_SIGNAL(&_M_val);
- _M_val.notify_all();
+ _AtomicRef(_M_val).notify_all();
_GLIBCXX_TSAN_MUTEX_POST_SIGNAL(&_M_val);
}
#endif
private:
- mutable __atomic_base<uintptr_t> _M_val{0};
+ using _AtomicRef = __atomic_ref<uintptr_t>;
+ alignas(_AtomicRef::required_alignment) mutable uintptr_t _M_val{0};
static constexpr uintptr_t _S_lock_bit{1};
};
- typename _Tp::element_type* _M_ptr = nullptr;
+ element_type* _M_ptr = nullptr;
_Atomic_count _M_refcount;
static typename _Atomic_count::pointer
@@ -608,7 +637,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
auto __pi = _M_refcount.lock(memory_order_acquire);
if (_M_ptr == __old._M_ptr && __pi == __old._M_refcount._M_pi)
- _M_refcount._M_wait_unlock(__o);
+ _M_refcount._M_wait_unlock(_M_ptr, __o);
else
_M_refcount.unlock(memory_order_relaxed);
}
diff --git a/libstdc++-v3/include/bits/std_mutex.h b/libstdc++-v3/include/bits/std_mutex.h
index 777097b..5f9f154 100644
--- a/libstdc++-v3/include/bits/std_mutex.h
+++ b/libstdc++-v3/include/bits/std_mutex.h
@@ -39,6 +39,7 @@
#else
#include <errno.h> // EBUSY
+#include <bits/chrono.h>
#include <bits/functexcept.h>
#include <bits/gthr.h>
@@ -210,8 +211,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__gthread_cond_t _M_cond;
#endif
};
- /// @endcond
+namespace chrono
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
+ // Convert a time_point to an absolute time represented as __gthread_time_t
+ // (which is typically just a typedef for struct timespec).
+ template<typename _Clock, typename _Dur>
+ [[__nodiscard__]] _GLIBCXX14_CONSTEXPR inline
+ __gthread_time_t
+ __to_timeout_gthread_time_t(const time_point<_Clock, _Dur>& __t)
+ {
+ auto __ts = chrono::__to_timeout_timespec(__t.time_since_epoch());
+ if constexpr (is_same<::timespec, __gthread_time_t>::value)
+ return __ts;
+ else if constexpr (is_convertible<::timespec, __gthread_time_t>::value)
+ return __ts;
+ else if constexpr (is_scalar<__gthread_time_t>::value) // Assume seconds:
+ return static_cast<__gthread_time_t>(__ts.tv_sec);
+ else // Assume this works and the members are in the correct order:
+ return __gthread_time_t{ __ts.tv_sec, __ts.tv_nsec };
+ }
+#pragma GCC diagnostic pop
+}
+ /// @endcond
#endif // _GLIBCXX_HAS_GTHREADS
/// Do not acquire ownership of the mutex.
diff --git a/libstdc++-v3/include/bits/stl_map.h b/libstdc++-v3/include/bits/stl_map.h
index 68c23b8..62d66ce 100644
--- a/libstdc++-v3/include/bits/stl_map.h
+++ b/libstdc++-v3/include/bits/stl_map.h
@@ -1259,7 +1259,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x)
{ return _M_t.find(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
find(const _Kt& __x) -> decltype(_M_t._M_find_tr(__x))
@@ -1284,7 +1284,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x) const
{ return _M_t.find(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
find(const _Kt& __x) const -> decltype(_M_t._M_find_tr(__x))
@@ -1305,7 +1305,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
count(const key_type& __x) const
{ return _M_t.find(__x) == _M_t.end() ? 0 : 1; }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
count(const _Kt& __x) const -> decltype(_M_t._M_count_tr(__x))
@@ -1348,7 +1348,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
lower_bound(const key_type& __x)
{ return _M_t.lower_bound(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
lower_bound(const _Kt& __x)
@@ -1373,7 +1373,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
lower_bound(const key_type& __x) const
{ return _M_t.lower_bound(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
lower_bound(const _Kt& __x) const
@@ -1393,7 +1393,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
upper_bound(const key_type& __x)
{ return _M_t.upper_bound(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
upper_bound(const _Kt& __x)
@@ -1413,7 +1413,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
upper_bound(const key_type& __x) const
{ return _M_t.upper_bound(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
upper_bound(const _Kt& __x) const
@@ -1442,7 +1442,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x)
{ return _M_t.equal_range(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
equal_range(const _Kt& __x)
@@ -1471,7 +1471,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x) const
{ return _M_t.equal_range(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
equal_range(const _Kt& __x) const
@@ -1649,7 +1649,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
_GLIBCXX_END_NAMESPACE_CONTAINER
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
// Allow std::map access to internals of compatible maps.
template<typename _Key, typename _Val, typename _Cmp1, typename _Alloc,
typename _Cmp2>
diff --git a/libstdc++-v3/include/bits/stl_multimap.h b/libstdc++-v3/include/bits/stl_multimap.h
index 4ee4a84..b2ae2ba 100644
--- a/libstdc++-v3/include/bits/stl_multimap.h
+++ b/libstdc++-v3/include/bits/stl_multimap.h
@@ -891,7 +891,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x)
{ return _M_t.find(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
find(const _Kt& __x) -> decltype(_M_t._M_find_tr(__x))
@@ -915,7 +915,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x) const
{ return _M_t.find(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
find(const _Kt& __x) const -> decltype(_M_t._M_find_tr(__x))
@@ -933,7 +933,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
count(const key_type& __x) const
{ return _M_t.count(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
count(const _Kt& __x) const -> decltype(_M_t._M_count_tr(__x))
@@ -976,7 +976,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
lower_bound(const key_type& __x)
{ return _M_t.lower_bound(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
lower_bound(const _Kt& __x)
@@ -1001,7 +1001,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
lower_bound(const key_type& __x) const
{ return _M_t.lower_bound(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
lower_bound(const _Kt& __x) const
@@ -1021,7 +1021,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
upper_bound(const key_type& __x)
{ return _M_t.upper_bound(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
upper_bound(const _Kt& __x)
@@ -1041,7 +1041,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
upper_bound(const key_type& __x) const
{ return _M_t.upper_bound(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
upper_bound(const _Kt& __x) const
@@ -1068,7 +1068,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x)
{ return _M_t.equal_range(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
equal_range(const _Kt& __x)
@@ -1095,7 +1095,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x) const
{ return _M_t.equal_range(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
equal_range(const _Kt& __x) const
@@ -1272,7 +1272,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
_GLIBCXX_END_NAMESPACE_CONTAINER
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
// Allow std::multimap access to internals of compatible maps.
template<typename _Key, typename _Val, typename _Cmp1, typename _Alloc,
typename _Cmp2>
diff --git a/libstdc++-v3/include/bits/stl_multiset.h b/libstdc++-v3/include/bits/stl_multiset.h
index 31451ab..b6e1bfc 100644
--- a/libstdc++-v3/include/bits/stl_multiset.h
+++ b/libstdc++-v3/include/bits/stl_multiset.h
@@ -773,7 +773,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
count(const key_type& __x) const
{ return _M_t.count(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
count(const _Kt& __x) const -> decltype(_M_t._M_count_tr(__x))
@@ -822,7 +822,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x) const
{ return _M_t.find(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
find(const _Kt& __x)
@@ -857,7 +857,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
lower_bound(const key_type& __x) const
{ return _M_t.lower_bound(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
lower_bound(const _Kt& __x)
@@ -887,7 +887,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
upper_bound(const key_type& __x) const
{ return _M_t.upper_bound(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
upper_bound(const _Kt& __x)
@@ -926,7 +926,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x) const
{ return _M_t.equal_range(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
equal_range(const _Kt& __x)
@@ -1103,7 +1103,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
_GLIBCXX_END_NAMESPACE_CONTAINER
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
// Allow std::multiset access to internals of compatible sets.
template<typename _Val, typename _Cmp1, typename _Alloc, typename _Cmp2>
struct
diff --git a/libstdc++-v3/include/bits/stl_set.h b/libstdc++-v3/include/bits/stl_set.h
index b65d631..f03d9e5 100644
--- a/libstdc++-v3/include/bits/stl_set.h
+++ b/libstdc++-v3/include/bits/stl_set.h
@@ -794,7 +794,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
count(const key_type& __x) const
{ return _M_t.find(__x) == _M_t.end() ? 0 : 1; }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
count(const _Kt& __x) const
@@ -844,7 +844,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x) const
{ return _M_t.find(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
find(const _Kt& __x)
@@ -879,7 +879,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
lower_bound(const key_type& __x) const
{ return _M_t.lower_bound(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
lower_bound(const _Kt& __x)
@@ -909,7 +909,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
upper_bound(const key_type& __x) const
{ return _M_t.upper_bound(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
upper_bound(const _Kt& __x)
@@ -948,7 +948,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x) const
{ return _M_t.equal_range(__x); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt>
auto
equal_range(const _Kt& __x)
@@ -1119,7 +1119,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
_GLIBCXX_END_NAMESPACE_CONTAINER
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
// Allow std::set access to internals of compatible sets.
template<typename _Val, typename _Cmp1, typename _Alloc, typename _Cmp2>
struct
diff --git a/libstdc++-v3/include/bits/stl_tree.h b/libstdc++-v3/include/bits/stl_tree.h
index 4b7f482..e78fa1d 100644
--- a/libstdc++-v3/include/bits/stl_tree.h
+++ b/libstdc++-v3/include/bits/stl_tree.h
@@ -1918,7 +1918,7 @@ namespace __rb_tree
pair<const_iterator, const_iterator>
equal_range(const key_type& __k) const;
-#if __cplusplus >= 201402L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req = __has_is_transparent_t<_Compare, _Kt>>
iterator
@@ -2007,7 +2007,7 @@ namespace __rb_tree
++__high;
return { __low, __high };
}
-#endif
+#endif // __glibcxx_generic_associative_lookup
// Debugging.
bool
diff --git a/libstdc++-v3/include/bits/this_thread_sleep.h b/libstdc++-v3/include/bits/this_thread_sleep.h
index 57f89f8..01f25dd 100644
--- a/libstdc++-v3/include/bits/this_thread_sleep.h
+++ b/libstdc++-v3/include/bits/this_thread_sleep.h
@@ -36,6 +36,7 @@
#if __cplusplus >= 201103L
#include <bits/chrono.h> // std::chrono::*
+#include <ext/numeric_traits.h> // __int_traits
#ifdef _GLIBCXX_USE_NANOSLEEP
# include <cerrno> // errno, EINTR
@@ -59,11 +60,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
#ifndef _GLIBCXX_NO_SLEEP
-#ifndef _GLIBCXX_USE_NANOSLEEP
- void
- __sleep_for(chrono::seconds, chrono::nanoseconds);
-#endif
-
/// this_thread::sleep_for
template<typename _Rep, typename _Period>
inline void
@@ -71,18 +67,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
if (__rtime <= __rtime.zero())
return;
- auto __s = chrono::duration_cast<chrono::seconds>(__rtime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__rtime - __s);
+
+ struct timespec __ts = chrono::__to_timeout_timespec(__rtime);
#ifdef _GLIBCXX_USE_NANOSLEEP
- struct ::timespec __ts =
- {
- static_cast<std::time_t>(__s.count()),
- static_cast<long>(__ns.count())
- };
while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
{ }
#else
- __sleep_for(__s, __ns);
+ using chrono::seconds;
+ using chrono::nanoseconds;
+ void __sleep_for(seconds __s, nanoseconds __ns);
+ __sleep_for(seconds(__ts.tv_sec), nanoseconds(__ts.tv_nsec));
#endif
}
diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h
index cc9e2c4..b9b2772 100644
--- a/libstdc++-v3/include/bits/unordered_map.h
+++ b/libstdc++-v3/include/bits/unordered_map.h
@@ -961,7 +961,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x)
{ return _M_h.find(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
find(const _Kt& __x) -> decltype(_M_h._M_find_tr(__x))
@@ -972,7 +972,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x) const
{ return _M_h.find(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
find(const _Kt& __x) const -> decltype(_M_h._M_find_tr(__x))
@@ -994,7 +994,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
count(const key_type& __x) const
{ return _M_h.count(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
count(const _Kt& __x) const -> decltype(_M_h._M_count_tr(__x))
@@ -1034,7 +1034,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x)
{ return _M_h.equal_range(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
equal_range(const _Kt& __x)
@@ -1046,7 +1046,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x) const
{ return _M_h.equal_range(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
equal_range(const _Kt& __x) const
@@ -2039,7 +2039,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x)
{ return _M_h.find(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
find(const _Kt& __x) -> decltype(_M_h._M_find_tr(__x))
@@ -2050,7 +2050,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x) const
{ return _M_h.find(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
find(const _Kt& __x) const -> decltype(_M_h._M_find_tr(__x))
@@ -2068,7 +2068,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
count(const key_type& __x) const
{ return _M_h.count(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
count(const _Kt& __x) const -> decltype(_M_h._M_count_tr(__x))
@@ -2106,7 +2106,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x)
{ return _M_h.equal_range(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
equal_range(const _Kt& __x)
@@ -2118,7 +2118,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x) const
{ return _M_h.equal_range(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
equal_range(const _Kt& __x) const
diff --git a/libstdc++-v3/include/bits/unordered_set.h b/libstdc++-v3/include/bits/unordered_set.h
index 5649dd7..29bc49a 100644
--- a/libstdc++-v3/include/bits/unordered_set.h
+++ b/libstdc++-v3/include/bits/unordered_set.h
@@ -744,7 +744,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x)
{ return _M_h.find(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
find(const _Kt& __k)
@@ -756,7 +756,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x) const
{ return _M_h.find(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
find(const _Kt& __k) const
@@ -779,7 +779,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
count(const key_type& __x) const
{ return _M_h.count(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
count(const _Kt& __k) const
@@ -820,7 +820,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x)
{ return _M_h.equal_range(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
equal_range(const _Kt& __k)
@@ -832,7 +832,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x) const
{ return _M_h.equal_range(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
equal_range(const _Kt& __k) const
@@ -1745,7 +1745,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x)
{ return _M_h.find(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
find(const _Kt& __x)
@@ -1757,7 +1757,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
find(const key_type& __x) const
{ return _M_h.find(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
find(const _Kt& __x) const
@@ -1776,7 +1776,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
count(const key_type& __x) const
{ return _M_h.count(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
count(const _Kt& __x) const -> decltype(_M_h._M_count_tr(__x))
@@ -1814,7 +1814,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x)
{ return _M_h.equal_range(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
equal_range(const _Kt& __x)
@@ -1826,7 +1826,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
equal_range(const key_type& __x) const
{ return _M_h.equal_range(__x); }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt>
auto
equal_range(const _Kt& __x) const
diff --git a/libstdc++-v3/include/debug/map.h b/libstdc++-v3/include/debug/map.h
index 985a7ac..30469b0 100644
--- a/libstdc++-v3/include/debug/map.h
+++ b/libstdc++-v3/include/debug/map.h
@@ -455,7 +455,7 @@ namespace __debug
}
#endif // C++17
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
using node_type = typename _Base::node_type;
using insert_return_type = _Node_insert_return<iterator, node_type>;
@@ -601,7 +601,7 @@ namespace __debug
find(const key_type& __x)
{ return iterator(_Base::find(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -614,7 +614,7 @@ namespace __debug
find(const key_type& __x) const
{ return const_iterator(_Base::find(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -629,7 +629,7 @@ namespace __debug
lower_bound(const key_type& __x)
{ return iterator(_Base::lower_bound(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -642,7 +642,7 @@ namespace __debug
lower_bound(const key_type& __x) const
{ return const_iterator(_Base::lower_bound(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -655,7 +655,7 @@ namespace __debug
upper_bound(const key_type& __x)
{ return iterator(_Base::upper_bound(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -668,7 +668,7 @@ namespace __debug
upper_bound(const key_type& __x) const
{ return const_iterator(_Base::upper_bound(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -686,7 +686,7 @@ namespace __debug
iterator(__res.second, this));
}
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -707,7 +707,7 @@ namespace __debug
const_iterator(__res.second, this));
}
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
diff --git a/libstdc++-v3/include/debug/multimap.h b/libstdc++-v3/include/debug/multimap.h
index c187e51..db9e246 100644
--- a/libstdc++-v3/include/debug/multimap.h
+++ b/libstdc++-v3/include/debug/multimap.h
@@ -340,7 +340,7 @@ namespace __debug
_Base::insert(__first, __last);
}
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
using node_type = typename _Base::node_type;
node_type
@@ -483,7 +483,7 @@ namespace __debug
find(const key_type& __x)
{ return iterator(_Base::find(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -496,7 +496,7 @@ namespace __debug
find(const key_type& __x) const
{ return const_iterator(_Base::find(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -511,7 +511,7 @@ namespace __debug
lower_bound(const key_type& __x)
{ return iterator(_Base::lower_bound(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -524,7 +524,7 @@ namespace __debug
lower_bound(const key_type& __x) const
{ return const_iterator(_Base::lower_bound(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -537,7 +537,7 @@ namespace __debug
upper_bound(const key_type& __x)
{ return iterator(_Base::upper_bound(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -550,7 +550,7 @@ namespace __debug
upper_bound(const key_type& __x) const
{ return const_iterator(_Base::upper_bound(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -568,7 +568,7 @@ namespace __debug
iterator(__res.second, this));
}
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -589,7 +589,7 @@ namespace __debug
const_iterator(__res.second, this));
}
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
diff --git a/libstdc++-v3/include/debug/multiset.h b/libstdc++-v3/include/debug/multiset.h
index 41bf78d..156378a 100644
--- a/libstdc++-v3/include/debug/multiset.h
+++ b/libstdc++-v3/include/debug/multiset.h
@@ -311,7 +311,7 @@ namespace __debug
{ _Base::insert(__l); }
#endif
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
using node_type = typename _Base::node_type;
node_type
@@ -457,7 +457,7 @@ namespace __debug
find(const key_type& __x) const
{ return const_iterator(_Base::find(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -485,7 +485,7 @@ namespace __debug
lower_bound(const key_type& __x) const
{ return const_iterator(_Base::lower_bound(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -511,7 +511,7 @@ namespace __debug
upper_bound(const key_type& __x) const
{ return const_iterator(_Base::upper_bound(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -547,7 +547,7 @@ namespace __debug
const_iterator(__res.second, this));
}
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
diff --git a/libstdc++-v3/include/debug/set.h b/libstdc++-v3/include/debug/set.h
index 6ec8338..9b42862 100644
--- a/libstdc++-v3/include/debug/set.h
+++ b/libstdc++-v3/include/debug/set.h
@@ -319,7 +319,7 @@ namespace __debug
{ _Base::insert(__l); }
#endif
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
using node_type = typename _Base::node_type;
using insert_return_type = _Node_insert_return<iterator, node_type>;
@@ -468,7 +468,7 @@ namespace __debug
find(const key_type& __x) const
{ return const_iterator(_Base::find(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -496,7 +496,7 @@ namespace __debug
lower_bound(const key_type& __x) const
{ return const_iterator(_Base::lower_bound(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -522,7 +522,7 @@ namespace __debug
upper_bound(const key_type& __x) const
{ return const_iterator(_Base::upper_bound(__x), this); }
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
@@ -558,7 +558,7 @@ namespace __debug
const_iterator(__res.second, this));
}
-#if __cplusplus > 201103L
+#ifdef __glibcxx_generic_associative_lookup // C++ >= 14
template<typename _Kt,
typename _Req =
typename __has_is_transparent<_Compare, _Kt>::type>
diff --git a/libstdc++-v3/include/debug/unordered_map b/libstdc++-v3/include/debug/unordered_map
index 7673db1..c90e44a 100644
--- a/libstdc++-v3/include/debug/unordered_map
+++ b/libstdc++-v3/include/debug/unordered_map
@@ -561,7 +561,7 @@ namespace __debug
}
#endif // C++17
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
using node_type = typename _Base::node_type;
using insert_return_type = _Node_insert_return<iterator, node_type>;
@@ -632,7 +632,7 @@ namespace __debug
find(const key_type& __key)
{ return { _Base::find(__key), this }; }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -645,7 +645,7 @@ namespace __debug
find(const key_type& __key) const
{ return { _Base::find(__key), this }; }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -666,7 +666,7 @@ namespace __debug
return { { __res.first, this }, { __res.second, this } };
}
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -685,7 +685,7 @@ namespace __debug
return { { __res.first, this }, { __res.second, this } };
}
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -790,7 +790,7 @@ namespace __debug
return __next;
}
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
node_type
_M_extract(_Base_const_iterator __victim)
{
@@ -1362,7 +1362,7 @@ namespace __debug
_M_check_rehashed(__bucket_count);
}
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
using node_type = typename _Base::node_type;
node_type
@@ -1428,7 +1428,7 @@ namespace __debug
find(const key_type& __key)
{ return { _Base::find(__key), this }; }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -1441,7 +1441,7 @@ namespace __debug
find(const key_type& __key) const
{ return { _Base::find(__key), this }; }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -1462,7 +1462,7 @@ namespace __debug
return { { __res.first, this }, { __res.second, this } };
}
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -1481,7 +1481,7 @@ namespace __debug
return { { __res.first, this }, { __res.second, this } };
}
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -1587,7 +1587,7 @@ namespace __debug
return __next;
}
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
node_type
_M_extract(_Base_const_iterator __victim)
{
diff --git a/libstdc++-v3/include/debug/unordered_set b/libstdc++-v3/include/debug/unordered_set
index 932600d..7fc4146 100644
--- a/libstdc++-v3/include/debug/unordered_set
+++ b/libstdc++-v3/include/debug/unordered_set
@@ -448,7 +448,7 @@ namespace __debug
_M_check_rehashed(__bucket_count);
}
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
using node_type = typename _Base::node_type;
using insert_return_type = _Node_insert_return<iterator, node_type>;
@@ -519,7 +519,7 @@ namespace __debug
find(const key_type& __key)
{ return { _Base::find(__key), this }; }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -532,7 +532,7 @@ namespace __debug
find(const key_type& __key) const
{ return { _Base::find(__key), this }; }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -554,7 +554,7 @@ namespace __debug
return { { __res.first, this }, { __res.second, this } };
}
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -573,7 +573,7 @@ namespace __debug
return { { __res.first, this }, { __res.second, this } };
}
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -672,7 +672,7 @@ namespace __debug
return __next;
}
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
node_type
_M_extract(_Base_const_iterator __victim)
{
@@ -1183,7 +1183,7 @@ namespace __debug
_M_check_rehashed(__bucket_count);
}
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
using node_type = typename _Base::node_type;
node_type
@@ -1249,7 +1249,7 @@ namespace __debug
find(const key_type& __key)
{ return { _Base::find(__key), this }; }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -1262,7 +1262,7 @@ namespace __debug
find(const key_type& __key) const
{ return { _Base::find(__key), this }; }
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -1284,7 +1284,7 @@ namespace __debug
return { { __res.first, this }, { __res.second, this } };
}
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -1303,7 +1303,7 @@ namespace __debug
return { { __res.first, this }, { __res.second, this } };
}
-#if __cplusplus > 201703L
+#ifdef __glibcxx_generic_unordered_lookup // C++ >= 20 && HOSTED
template<typename _Kt,
typename = std::__has_is_transparent_t<_Hash, _Kt>,
typename = std::__has_is_transparent_t<_Pred, _Kt>>
@@ -1400,7 +1400,7 @@ namespace __debug
return __next;
}
-#if __cplusplus > 201402L
+#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
node_type
_M_extract(_Base_const_iterator __victim)
{
diff --git a/libstdc++-v3/include/std/condition_variable b/libstdc++-v3/include/std/condition_variable
index 3525ff3..dcf0b92 100644
--- a/libstdc++-v3/include/std/condition_variable
+++ b/libstdc++-v3/include/std/condition_variable
@@ -193,15 +193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__wait_until_impl(unique_lock<mutex>& __lock,
const chrono::time_point<steady_clock, _Dur>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
_M_cond.wait_until(*__lock.mutex(), CLOCK_MONOTONIC, __ts);
return (steady_clock::now() < __atime
@@ -214,15 +206,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__wait_until_impl(unique_lock<mutex>& __lock,
const chrono::time_point<system_clock, _Dur>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
_M_cond.wait_until(*__lock.mutex(), __ts);
return (system_clock::now() < __atime
diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index 281c038..1102ac8 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -105,6 +105,7 @@ namespace __format
template<typename _CharT> class _Sink;
template<typename _CharT> class _Fixedbuf_sink;
template<typename _Out, typename _CharT> class _Padding_sink;
+ template<typename _Out, typename _CharT> class _Escaping_sink;
// Output iterator that writes to a type-erase character sink.
template<typename _CharT>
@@ -1068,6 +1069,17 @@ namespace __format
template<typename _Out, typename _CharT>
_Out
+ __write_escape_seqs(_Out __out, basic_string_view<_CharT> __units)
+ {
+ using _UChar = make_unsigned_t<_CharT>;
+ for (_CharT __c : __units)
+ __out = __format::__write_escape_seq(
+ __out, static_cast<_UChar>(__c), _Escapes<_CharT>::_S_x());
+ return __out;
+ }
+
+ template<typename _Out, typename _CharT>
+ _Out
__write_escaped_char(_Out __out, _CharT __c)
{
using _UChar = make_unsigned_t<_CharT>;
@@ -1124,12 +1136,10 @@ namespace __format
template<typename _CharT, typename _Out>
_Out
- __write_escaped_unicode(_Out __out,
- basic_string_view<_CharT> __str,
- _Term_char __term)
+ __write_escaped_unicode_part(_Out __out, basic_string_view<_CharT>& __str,
+ bool& __prev_esc, _Term_char __term)
{
using _Str_view = basic_string_view<_CharT>;
- using _UChar = make_unsigned_t<_CharT>;
using _Esc = _Escapes<_CharT>;
static constexpr char32_t __replace = U'\uFFFD';
@@ -1143,10 +1153,10 @@ namespace __format
}();
__unicode::_Utf_view<char32_t, _Str_view> __v(std::move(__str));
+ __str = {};
+
auto __first = __v.begin();
auto const __last = __v.end();
-
- bool __prev_esc = true;
while (__first != __last)
{
bool __esc_ascii = false;
@@ -1185,15 +1195,32 @@ namespace __format
__out = __format::__write_escaped_char(__out, *__first.base());
else if (__esc_unicode)
__out = __format::__write_escape_seq(__out, *__first, _Esc::_S_u());
- else // __esc_replace
- for (_CharT __c : _Str_view(__first.base(), __first._M_units()))
- __out = __format::__write_escape_seq(__out,
- static_cast<_UChar>(__c),
- _Esc::_S_x());
+ // __esc_replace
+ else if (_Str_view __units(__first.base(), __first._M_units());
+ __units.end() != __last.base())
+ __out = __format::__write_escape_seqs(__out, __units);
+ else
+ {
+ __str = __units;
+ return __out;
+ }
+
__prev_esc = true;
++__first;
-
}
+
+ return __out;
+ }
+
+ template<typename _CharT, typename _Out>
+ _Out
+ __write_escaped_unicode(_Out __out, basic_string_view<_CharT> __str,
+ _Term_char __term)
+ {
+ bool __prev_escape = true;
+ __out = __format::__write_escaped_unicode_part(__out, __str,
+ __prev_escape, __term);
+ __out = __format::__write_escape_seqs(__out, __str);
return __out;
}
@@ -1399,7 +1426,6 @@ namespace __format
_M_format_range(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const
{
using _Range = remove_reference_t<_Rg>;
- using _String = basic_string<_CharT>;
using _String_view = basic_string_view<_CharT>;
if constexpr (!is_lvalue_reference_v<_Rg>)
return _M_format_range<_Range&>(__rg, __fc);
@@ -1412,55 +1438,28 @@ namespace __format
size_t(ranges::distance(__rg)));
return format(__str, __fc);
}
- else if (!_M_spec._M_debug)
+ else
{
+ auto __handle_debug = [this, &__rg]<typename _NOut>(_NOut __nout)
+ {
+ if (!_M_spec._M_debug)
+ return ranges::copy(__rg, std::move(__nout)).out;
+
+ _Escaping_sink<_NOut, _CharT>
+ __sink(std::move(__nout), _Term_quote);
+ ranges::copy(__rg, __sink.out());
+ return __sink._M_finish();
+ };
+
const size_t __padwidth = _M_spec._M_get_width(__fc);
if (__padwidth == 0 && _M_spec._M_prec_kind == _WP_none)
- return ranges::copy(__rg, __fc.out()).out;
+ return __handle_debug(__fc.out());
- _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth,
- _M_spec._M_get_precision(__fc));
- ranges::copy(__rg, __sink.out());
+ _Padding_sink<_Out, _CharT>
+ __sink(__fc.out(), __padwidth, _M_spec._M_get_precision(__fc));
+ __handle_debug(__sink.out());
return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill);
}
- else if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
- {
- const size_t __n(ranges::distance(__rg));
- size_t __w = __n;
- if constexpr (!__unicode::__literal_encoding_is_unicode<_CharT>())
- if (size_t __max = _M_spec._M_get_precision(__fc); __n > __max)
- __w == __max;
-
- if (__w <= __format::__stackbuf_size<_CharT>)
- {
- _CharT __buf[__format::__stackbuf_size<_CharT>];
- ranges::copy_n(ranges::begin(__rg), __w, __buf);
- return _M_format_escaped(_String_view(__buf, __n), __fc);
- }
- else if constexpr (ranges::random_access_range<_Rg>)
- {
- ranges::iterator_t<_Rg> __first = ranges::begin(__rg);
- ranges::subrange __sub(__first, ranges::next(__first, __w));
- return _M_format_escaped(_String(from_range, __sub), __fc);
- }
- else if (__w <= __n)
- {
- ranges::subrange __sub(
- counted_iterator(ranges::begin(__rg), __w),
- default_sentinel);
- return _M_format_escaped(_String(from_range, __sub), __fc);
- }
- else if constexpr (ranges::sized_range<_Rg>)
- return _M_format_escaped(_String(from_range, __rg), __fc);
- else
- {
- // N.B. preserve the computed size
- ranges::subrange __sub(__rg, __n);
- return _M_format_escaped(_String(from_range, __sub), __fc);
- }
- }
- else
- return _M_format_escaped(_String(from_range, __rg), __fc);
}
constexpr void
@@ -3997,6 +3996,93 @@ namespace __format
}
};
+ template<typename _Out, typename _CharT>
+ class _Escaping_sink : public _Buf_sink<_CharT>
+ {
+ using _Esc = _Escapes<_CharT>;
+
+ _Out _M_out;
+ _Term_char _M_term : 2;
+ unsigned _M_prev_escape : 1;
+ unsigned _M_out_discards : 1;
+
+ void
+ _M_sync_discarding()
+ {
+ if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
+ _M_out_discards = _M_out._M_discarding();
+ }
+
+ void
+ _M_write()
+ {
+ span<_CharT> __bytes = this->_M_used();
+ basic_string_view<_CharT> __str(__bytes.data(), __bytes.size());
+
+ size_t __rem = 0;
+ if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
+ {
+ bool __prev_escape = _M_prev_escape;
+ _M_out = __format::__write_escaped_unicode_part(
+ std::move(_M_out), __str, __prev_escape, _M_term);
+ _M_prev_escape = __prev_escape;
+
+ __rem = __str.size();
+ if (__rem > 0 && __str.data() != this->_M_buf) [[unlikely]]
+ ranges::move(__str, this->_M_buf);
+ }
+ else
+ _M_out = __format::__write_escaped_ascii(
+ std::move(_M_out), __str, _M_term);
+
+ this->_M_reset(this->_M_buf, __rem);
+ _M_sync_discarding();
+ }
+
+ void
+ _M_overflow() override
+ {
+ if (_M_out_discards)
+ this->_M_rewind();
+ else
+ _M_write();
+ }
+
+ bool
+ _M_discarding() const override
+ { return _M_out_discards; }
+
+ public:
+ [[__gnu__::__always_inline__]]
+ explicit
+ _Escaping_sink(_Out __out, _Term_char __term)
+ : _M_out(std::move(__out)), _M_term(__term),
+ _M_prev_escape(true), _M_out_discards(false)
+ {
+ _M_out = __format::__write(std::move(_M_out), _Esc::_S_term(_M_term));
+ _M_sync_discarding();
+ }
+
+ _Out
+ _M_finish()
+ {
+ if (_M_out_discards)
+ return std::move(_M_out);
+
+ if (!this->_M_used().empty())
+ {
+ _M_write();
+ if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
+ if (auto __rem = this->_M_used(); !__rem.empty())
+ {
+ basic_string_view<_CharT> __str(__rem.data(), __rem.size());
+ _M_out = __format::__write_escape_seqs(std::move(_M_out), __str);
+ }
+ }
+ return __format::__write(std::move(_M_out), _Esc::_S_term(_M_term));
+ }
+ };
+
enum class _Arg_t : unsigned char {
_Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull,
_Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr, _Arg_handle,
diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex
index 631c380..d4fc4c6 100644
--- a/libstdc++-v3/include/std/mutex
+++ b/libstdc++-v3/include/std/mutex
@@ -179,14 +179,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_try_lock_until(const chrono::time_point<chrono::system_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts = {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
return static_cast<_Derived*>(this)->_M_timedlock(__ts);
}
@@ -196,14 +189,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_try_lock_until(const chrono::time_point<chrono::steady_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts = {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
return static_cast<_Derived*>(this)->_M_clocklock(CLOCK_MONOTONIC,
__ts);
}
diff --git a/libstdc++-v3/include/std/shared_mutex b/libstdc++-v3/include/std/shared_mutex
index 94c8532..a267ad7 100644
--- a/libstdc++-v3/include/std/shared_mutex
+++ b/libstdc++-v3/include/std/shared_mutex
@@ -520,15 +520,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
try_lock_until(const chrono::time_point<chrono::system_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ struct timespec __ts = chrono::__to_timeout_timespec(__atime);
int __ret = __glibcxx_rwlock_timedwrlock(&_M_rwlock, &__ts);
// On self-deadlock, we just fail to acquire the lock. Technically,
// the program violated the precondition.
@@ -546,15 +538,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
try_lock_until(const chrono::time_point<chrono::steady_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ struct timespec __ts = chrono::__to_timeout_timespec(__atime);
int __ret = pthread_rwlock_clockwrlock(&_M_rwlock, CLOCK_MONOTONIC,
&__ts);
// On self-deadlock, we just fail to acquire the lock. Technically,
@@ -596,14 +580,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
try_lock_shared_until(const chrono::time_point<chrono::system_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
+ struct timespec __ts = chrono::__to_timeout_timespec(__atime);
int __ret;
// Unlike for lock(), we are not allowed to throw an exception so if
@@ -636,15 +613,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
try_lock_shared_until(const chrono::time_point<chrono::steady_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ struct timespec __ts = chrono::__to_timeout_timespec(__atime);
int __ret = pthread_rwlock_clockrdlock(&_M_rwlock, CLOCK_MONOTONIC,
&__ts);
// On self-deadlock, we just fail to acquire the lock. Technically,
diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index e5336b7..1822d42 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -287,7 +287,11 @@ class SharedPointerPrinter(printer_base):
def _get_refcounts(self):
if self._typename == 'std::atomic':
# A tagged pointer is stored as uintptr_t.
- ptr_val = self._val['_M_refcount']['_M_val']['_M_i']
+ val = self._val['_M_refcount']['_M_val']
+ if val.type.is_scalar: # GCC 16 stores uintptr_t
+ ptr_val = val
+ else: # GCC 12-15 stores std::atomic<uintptr_t>
+ ptr_val = val['_M_i']
ptr_val = ptr_val - (ptr_val % 2) # clear lock bit
ptr_type = find_type(self._val['_M_refcount'].type, 'pointer')
return ptr_val.cast(ptr_type)
diff --git a/libstdc++-v3/src/c++11/thread.cc b/libstdc++-v3/src/c++11/thread.cc
index 6c2ec29..5cfe564 100644
--- a/libstdc++-v3/src/c++11/thread.cc
+++ b/libstdc++-v3/src/c++11/thread.cc
@@ -231,10 +231,30 @@ namespace std _GLIBCXX_VISIBILITY(default)
_GLIBCXX_BEGIN_NAMESPACE_VERSION
namespace this_thread
{
+namespace
+{
+ // returns min(s, Dur::max())
+ template<typename Dur>
+ inline chrono::seconds
+ limit(chrono::seconds s)
+ {
+ static_assert(ratio_equal<typename Dur::period, ratio<1>>::value,
+ "period must be seconds to avoid potential overflow");
+
+ if (s > Dur::max()) [[__unlikely__]]
+ s = chrono::duration_cast<chrono::seconds>(Dur::max());
+ return s;
+ }
+}
+
void
__sleep_for(chrono::seconds __s, chrono::nanoseconds __ns)
{
#ifdef _GLIBCXX_USE_NANOSLEEP
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
+ if constexpr (is_integral<time_t>::value) // POSIX.1-2001 allows floating
+ __s = limit<chrono::duration<time_t>>(__s);
+
struct ::timespec __ts =
{
static_cast<std::time_t>(__s.count()),
@@ -246,6 +266,8 @@ namespace this_thread
const auto target = chrono::steady_clock::now() + __s + __ns;
while (true)
{
+ __s = limit<chrono::duration<unsigned>>(__s);
+
unsigned secs = __s.count();
if (__ns.count() > 0)
{
@@ -271,12 +293,28 @@ namespace this_thread
break;
__s = chrono::duration_cast<chrono::seconds>(target - now);
__ns = chrono::duration_cast<chrono::nanoseconds>(target - (now + __s));
- }
+ }
#elif defined(_GLIBCXX_USE_WIN32_SLEEP)
- unsigned long ms = __ns.count() / 1000000;
- if (__ns.count() > 0 && ms == 0)
- ms = 1;
- ::Sleep(chrono::milliseconds(__s).count() + ms);
+
+ // Can't use limit<chrono::milliseconds>(__s) here because it would
+ // multiply __s by 1000 which could overflow.
+ // Limit to milliseconds::max() and truncate to seconds:
+ chrono::milliseconds ms = chrono::milliseconds::max();
+ if (__s < chrono::duration_cast<chrono::seconds>(ms))
+ {
+ ms = __s;
+ ms += chrono::__detail::ceil<chrono::milliseconds>(__ns);
+ }
+
+ // Use Sleep(DWORD millis) where DWORD is uint32_t.
+ constexpr chrono::milliseconds max_sleep(INFINITE - 1u);
+ while (ms > max_sleep)
+ {
+ ::Sleep(max_sleep.count());
+ ms -= max_sleep;
+ }
+
+ ::Sleep(ms.count());
#endif
}
}
diff --git a/libstdc++-v3/src/c++17/fs_path.cc b/libstdc++-v3/src/c++17/fs_path.cc
index 215afa0..03bb5ec 100644
--- a/libstdc++-v3/src/c++17/fs_path.cc
+++ b/libstdc++-v3/src/c++17/fs_path.cc
@@ -34,6 +34,7 @@
#include <filesystem>
#include <algorithm>
#include <array>
+#include <new>
#include <bits/stl_uninitialized.h>
#include <ext/numeric_traits.h> // __gnu_cxx::__int_traits
@@ -207,6 +208,10 @@ struct path::_List::_Impl
_Impl(int cap) : _M_size(0), _M_capacity(cap) { }
+ ~_Impl() { clear(); }
+
+ // Align the first member like the value_type so that we can store one or
+ // more objects of that type immediately after the memory occupied by *this.
alignas(value_type) int _M_size;
int _M_capacity;
@@ -246,29 +251,67 @@ struct path::_List::_Impl
unique_ptr<_Impl, _Impl_deleter> copy() const
{
const auto n = size();
- void* p = ::operator new(sizeof(_Impl) + n * sizeof(value_type));
- unique_ptr<_Impl, _Impl_deleter> newptr(::new (p) _Impl{n});
+ // *this already has n elements so don't need to check if n overflows:
+ auto newptr = create_unchecked(n);
std::uninitialized_copy_n(begin(), n, newptr->begin());
newptr->_M_size = n;
return newptr;
}
+ // We use the two least significant bits to store a _Type value so
+ // require memory aligned to at least 4 bytes:
+ static_assert(__STDCPP_DEFAULT_NEW_ALIGNMENT__ >= 4);
+ // Require memory suitably aligned for an _Impl and its value types:
+ static_assert(__STDCPP_DEFAULT_NEW_ALIGNMENT__ >= alignof(value_type));
+
// Clear the lowest two bits from the pointer (i.e. remove the _Type value)
static _Impl* notype(_Impl* p)
{
constexpr uintptr_t mask = ~(uintptr_t)0x3;
return reinterpret_cast<_Impl*>(reinterpret_cast<uintptr_t>(p) & mask);
}
+
+ // Create a new _Impl with capacity for n components.
+ static unique_ptr<_Impl, _Impl_deleter>
+ create(int n)
+ {
+ using __gnu_cxx::__int_traits;
+ // Nobody should need paths with this many components.
+ if (n >= __int_traits<int>::__max / 4)
+ std::__throw_bad_alloc();
+
+ if constexpr (__int_traits<int>::__max >= __int_traits<size_t>::__max)
+ {
+ // Check that the calculation in create_unchecked(n) won't overflow.
+ size_t bytes;
+ if (__builtin_mul_overflow(n, sizeof(value_type), &bytes)
+ || __builtin_add_overflow(sizeof(_Impl), bytes, &bytes))
+ std::__throw_bad_alloc();
+ }
+ // Otherwise, it can't overflow, even for 20-bit size_t on msp430.
+
+ return create_unchecked(n);
+ }
+
+ // pre: no overflow in Si + n * Sv
+ static unique_ptr<_Impl, _Impl_deleter>
+ create_unchecked(int n)
+ {
+ void* p = ::operator new(sizeof(_Impl) + n * sizeof(value_type));
+ return std::unique_ptr<_Impl, _Impl_deleter>(::new(p) _Impl{n});
+ }
};
-void path::_List::_Impl_deleter::operator()(_Impl* p) const noexcept
+// Destroy and deallocate an _Impl.
+void
+path::_List::_Impl_deleter::operator()(_Impl* p) const noexcept
{
p = _Impl::notype(p);
if (p)
{
- __glibcxx_assert(p->_M_size <= p->_M_capacity);
- p->clear();
- ::operator delete(p, sizeof(*p) + p->_M_capacity * sizeof(value_type));
+ const auto n = p->_M_capacity;
+ p->~_Impl();
+ ::operator delete(p, sizeof(_Impl) + n * sizeof(_Impl::value_type));
}
}
@@ -455,24 +498,7 @@ path::_List::reserve(int newcap, bool exact = false)
newcap = nextcap;
}
- using __gnu_cxx::__int_traits;
- // Nobody should need paths with this many components.
- if (newcap >= __int_traits<int>::__max / 4)
- std::__throw_bad_alloc();
-
- size_t bytes;
- if constexpr (__int_traits<int>::__max >= __int_traits<size_t>::__max)
- {
- size_t components;
- if (__builtin_mul_overflow(newcap, sizeof(value_type), &components)
- || __builtin_add_overflow(sizeof(_Impl), components, &bytes))
- std::__throw_bad_alloc();
- }
- else // This won't overflow, even for 20-bit size_t on msp430.
- bytes = sizeof(_Impl) + newcap * sizeof(value_type);
-
- void* p = ::operator new(bytes);
- std::unique_ptr<_Impl, _Impl_deleter> newptr(::new(p) _Impl{newcap});
+ auto newptr = _Impl::create(newcap);
const int cursize = curptr ? curptr->size() : 0;
if (cursize)
{
diff --git a/libstdc++-v3/src/c++20/atomic.cc b/libstdc++-v3/src/c++20/atomic.cc
index 4120e1a..7978809 100644
--- a/libstdc++-v3/src/c++20/atomic.cc
+++ b/libstdc++-v3/src/c++20/atomic.cc
@@ -350,14 +350,7 @@ __platform_wait_until(const __platform_wait_t* __addr,
__platform_wait_t __old,
const __wait_clock_t::time_point& __atime) noexcept
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- struct timespec __rt =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
+ struct timespec __rt = chrono::__to_timeout_timespec(__atime);
if (syscall (SYS_futex, __addr,
static_cast<int>(__futex_wait_flags::__wait_bitset_private),
@@ -378,14 +371,7 @@ bool
__cond_wait_until(__condvar& __cv, mutex& __mx,
const __wait_clock_t::time_point& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
if constexpr (is_same_v<chrono::steady_clock, __wait_clock_t>)
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/pr118757.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/pr118757.cc
new file mode 100644
index 0000000..d54abd8
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/pr118757.cc
@@ -0,0 +1,29 @@
+// { dg-do run { target c++20 } }
+// { dg-require-gthreads "" }
+// { dg-require-effective-target hosted }
+
+#include <memory>
+#include <chrono>
+#include <thread>
+#include <barrier>
+
+std::shared_ptr<int> q = std::make_shared<int>(42);
+std::atomic<std::shared_ptr<int>> p = q;
+
+std::barrier bar(2);
+
+void signaller()
+{
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ p.store(std::shared_ptr<int>(q, nullptr));
+ p.notify_one();
+ bar.arrive_and_wait();
+}
+
+int main(int, char**)
+{
+ std::thread thr(signaller);
+ p.wait(q);
+ bar.arrive_and_wait();
+ thr.join();
+}
diff --git a/libstdc++-v3/testsuite/20_util/weak_ptr/pr118757.cc b/libstdc++-v3/testsuite/20_util/weak_ptr/pr118757.cc
new file mode 100644
index 0000000..f048f13
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/weak_ptr/pr118757.cc
@@ -0,0 +1,30 @@
+// { dg-do run { target c++20 } }
+// { dg-require-gthreads "" }
+// { dg-require-effective-target hosted }
+
+#include <memory>
+#include <chrono>
+#include <thread>
+#include <barrier>
+
+std::shared_ptr<int> s = std::make_shared<int>(42);
+std::weak_ptr<int> q = s;
+std::atomic<std::weak_ptr<int>> p = q;
+
+std::barrier bar(2);
+
+void signaller()
+{
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ p.store(std::shared_ptr<int>(s, nullptr));
+ p.notify_one();
+ bar.arrive_and_wait();
+}
+
+int main(int, char**)
+{
+ std::thread thr(signaller);
+ p.wait(q);
+ bar.arrive_and_wait();
+ thr.join();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/condition_variable/members/116586.cc b/libstdc++-v3/testsuite/30_threads/condition_variable/members/116586.cc
new file mode 100644
index 0000000..7114007
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/condition_variable/members/116586.cc
@@ -0,0 +1,60 @@
+// { dg-do run { target c++11 } }
+
+#include <condition_variable>
+#include <chrono>
+#include <mutex>
+#include <initializer_list>
+#include <testsuite_hooks.h>
+
+namespace chrono = std::chrono;
+
+// thread.timedmutex.requirements.general:
+// If abs_time has already passed, the function attempts to obtain
+// ownership without blocking (as if by calling try_lock()).
+
+template <typename Clock>
+void
+test_absolute(chrono::nanoseconds offset)
+{
+ std::mutex mtx;
+ std::condition_variable cv;
+ chrono::time_point<Clock> tp(offset);
+ std::unique_lock<std::mutex> lock(mtx);
+ // Doesn't cope with spurious wakeup
+ VERIFY(cv.wait_until(lock, tp) == std::cv_status::timeout);
+}
+
+// The type of clock used for the actual wait depends on whether
+// _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK is defined. We might as well just test
+// both steady_clock and system_clock.
+template <typename Clock>
+void
+test_relative(chrono::nanoseconds offset)
+{
+ std::mutex mtx;
+ std::condition_variable cv;
+ const auto d = -Clock::now().time_since_epoch() + offset;
+ std::unique_lock<std::mutex> lock(mtx);
+ // Doesn't cope with spurious wakeup
+ VERIFY(cv.wait_for(lock, d) == std::cv_status::timeout);
+}
+
+int main()
+{
+ // It's not really possible to arrange for the relative calls to have
+ // tv_nsec == 0 due to time advancing.
+ for (const chrono::nanoseconds offset : {
+ // tv_sec == 0, tv_nsec == 0
+ chrono::nanoseconds{0},
+ // tv_sec == 0, tv_nsec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::milliseconds{-10}),
+ // tv_sec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::seconds{-10})
+ }) {
+ test_absolute<chrono::system_clock>(offset);
+ test_relative<chrono::system_clock>(offset);
+
+ test_absolute<chrono::steady_clock>(offset);
+ test_relative<chrono::steady_clock>(offset);
+ }
+}
diff --git a/libstdc++-v3/testsuite/30_threads/future/members/116586.cc b/libstdc++-v3/testsuite/30_threads/future/members/116586.cc
new file mode 100644
index 0000000..b7cd12c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/future/members/116586.cc
@@ -0,0 +1,55 @@
+// { dg-do run { target c++11 } }
+
+#include <future>
+#include <chrono>
+#include <initializer_list>
+#include <testsuite_hooks.h>
+
+namespace chrono = std::chrono;
+
+// thread.timedmutex.requirements.general:
+// If abs_time has already passed, the function attempts to obtain
+// ownership without blocking (as if by calling try_lock()).
+
+template <typename Clock>
+void
+test_absolute(chrono::nanoseconds offset)
+{
+ std::promise<int> p;
+ std::future<int> f = p.get_future();
+ const chrono::time_point<Clock> tp(offset);
+ VERIFY(f.wait_until(tp) == std::future_status::timeout);
+}
+
+// The type of clock used for the actual wait depends on whether
+// _GLIBCXX_HAVE_LINUX_FUTEX is defined. We might as well just test both
+// steady_clock and system_clock.
+template <typename Clock>
+void
+test_relative(chrono::nanoseconds offset)
+{
+ std::promise<int> p;
+ std::future<int> f = p.get_future();
+ const auto d = -Clock::now().time_since_epoch() + offset;
+ VERIFY(f.wait_for(d) == std::future_status::timeout);
+}
+
+int main()
+{
+ // It's not really possible to arrange for the relative calls to have tv_nsec
+ // == 0 due to time advancing.
+ for (const chrono::nanoseconds offset : {
+ // tv_sec == 0, tv_nsec == 0
+ chrono::nanoseconds{0},
+ // tv_sec == 0, tv_nsec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::milliseconds{-10}),
+ // tv_sec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::seconds{-10})
+ }) {
+ test_absolute<chrono::system_clock>(offset);
+ test_relative<chrono::system_clock>(offset);
+
+ test_absolute<chrono::steady_clock>(offset);
+ test_relative<chrono::steady_clock>(offset);
+ }
+}
diff --git a/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/116586.cc b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/116586.cc
new file mode 100644
index 0000000..941f3af
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/116586.cc
@@ -0,0 +1,72 @@
+// { dg-do run { target c++11 } }
+
+#include <mutex>
+#include <chrono>
+#include <future>
+#include <initializer_list>
+#include <testsuite_hooks.h>
+
+namespace chrono = std::chrono;
+
+// thread.timedmutex.requirements.general:
+// If abs_time has already passed, the function attempts to obtain
+// ownership without blocking (as if by calling try_lock()).
+
+template <typename Clock>
+void
+test_absolute(chrono::nanoseconds offset)
+{
+ std::recursive_timed_mutex mtx;
+ chrono::time_point<Clock> tp(offset);
+ VERIFY(mtx.try_lock_until(tp));
+
+ {
+ // To test failing to lock a recursive mutex we need to try to lock on a
+ // different thread.
+ auto t = std::async(std::launch::async, [&mtx, tp]() {
+ VERIFY(!mtx.try_lock_until(tp));
+ });
+ }
+}
+
+// The type of clock used for the actual wait depends on whether
+// _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK is defined. We might as well just test
+// both steady_clock and system_clock.
+template <typename Clock>
+void
+test_relative(chrono::nanoseconds offset)
+{
+ std::recursive_timed_mutex mtx;
+ const auto d = -Clock::now().time_since_epoch() + offset;
+ VERIFY(mtx.try_lock_for(d));
+
+ {
+ // To test failing to lock a recursive mutex we need to try to lock on a
+ // different thread.
+ auto t = std::async(std::launch::async, [&mtx, d]() {
+ VERIFY(!mtx.try_lock_for(d));
+ });
+ }
+}
+
+int main()
+{
+ // Try once with an offset that ought to result in tv_sec == 0, tv_nsec < 0
+ // and one with an offset that ought to result in tv_sec < 0, tv_nsec == 0
+ // for the absolute calls at least. It's not really possible to arrange for
+ // the relative calls to have tv_nsec == 0 due to time advancing.
+ for (const chrono::nanoseconds offset : {
+ // tv_sec == 0, tv_nsec == 0
+ chrono::nanoseconds{0},
+ // tv_sec == 0, tv_nsec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::milliseconds{-10}),
+ // tv_sec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::seconds{-10})
+ }) {
+ test_absolute<chrono::system_clock>(offset);
+ test_relative<chrono::system_clock>(offset);
+
+ test_absolute<chrono::steady_clock>(offset);
+ test_relative<chrono::steady_clock>(offset);
+ }
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
index 39681c7..94acb25 100644
--- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -24,6 +24,7 @@
#include <chrono>
#include <thread>
#include <atomic>
+#include <initializer_list>
#include <testsuite_hooks.h>
void test01()
@@ -90,9 +91,30 @@ test03()
s.try_acquire_for(timeout);
}
+// Prove semaphore doesn't suffer from PR116586
+template <typename Clock>
+void
+test_relative(std::chrono::nanoseconds offset)
+{
+ std::binary_semaphore sem(1);
+ VERIFY(sem.try_acquire_for(offset));
+ VERIFY(!sem.try_acquire_for(offset));
+}
+
int main()
{
test01();
test02();
test03();
+ using namespace std::chrono;
+ for (const nanoseconds offset : {
+ nanoseconds{0},
+ nanoseconds{-10ms},
+ nanoseconds{-10s}
+ }) {
+ test_relative<std::chrono::system_clock>(offset);
+ test_relative<std::chrono::system_clock>(offset - std::chrono::system_clock::now().time_since_epoch());
+ test_relative<std::chrono::steady_clock>(offset);
+ test_relative<std::chrono::steady_clock>(offset - std::chrono::steady_clock::now().time_since_epoch());
+ }
}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
index de0068d..ed6bd11 100644
--- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -24,6 +24,7 @@
#include <chrono>
#include <thread>
#include <atomic>
+#include <initializer_list>
#include <testsuite_hooks.h>
void test01()
@@ -87,8 +88,31 @@ void test02()
b.wait(1);
}
+// Prove semaphore doesn't suffer from PR116586
+template <typename Clock>
+void
+test_absolute(std::chrono::nanoseconds offset)
+{
+ std::binary_semaphore sem(1);
+ std::chrono::time_point<Clock> tp(offset);
+ VERIFY(sem.try_acquire_until(tp));
+ VERIFY(!sem.try_acquire_until(tp));
+}
+
int main()
{
test01();
test02();
+ using namespace std::chrono;
+ for (const nanoseconds offset : {
+ // tv_sec == 0, tv_nsec == 0
+ nanoseconds{0},
+ // tv_sec == 0, tv_nsec < 0
+ nanoseconds{-10ms},
+ // tv_sec < 0
+ nanoseconds{-10s}
+ }) {
+ test_absolute<std::chrono::system_clock>(offset);
+ test_absolute<std::chrono::steady_clock>(offset);
+ }
}
diff --git a/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/116586.cc b/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/116586.cc
new file mode 100644
index 0000000..cebbb3a
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/116586.cc
@@ -0,0 +1,97 @@
+// { dg-do run { target c++14 } }
+
+#include <shared_mutex>
+#include <chrono>
+#include <future>
+#include <initializer_list>
+#include <testsuite_hooks.h>
+
+namespace chrono = std::chrono;
+
+// thread.timedmutex.requirements.general:
+// If abs_time has already passed, the function attempts to obtain
+// ownership without blocking (as if by calling try_lock()).
+
+template <typename Clock>
+void
+test_exclusive_absolute(chrono::nanoseconds offset)
+{
+ std::shared_timed_mutex stm;
+ chrono::time_point<Clock> tp(offset);
+ VERIFY(stm.try_lock_until(tp));
+ VERIFY(!stm.try_lock_until(tp));
+}
+
+template <typename Clock>
+void
+test_shared_absolute(chrono::nanoseconds offset)
+{
+ std::shared_timed_mutex stm;
+ chrono::time_point<Clock> tp(offset);
+ VERIFY(stm.try_lock_shared_until(tp));
+ stm.unlock_shared();
+
+ VERIFY(stm.try_lock_for(chrono::seconds{10}));
+
+ {
+ // NPTL will give us EDEADLK if pthread_rwlock_timedrdlock() is called on
+ // the same thread that already holds the exclusive (write) lock, so let's
+ // arrange for a different thread to try to acquire the shared lock.
+ auto t = std::async(std::launch::async, [&stm, tp]() {
+ VERIFY(!stm.try_lock_shared_until(tp));
+ });
+ }
+}
+
+// The type of clock used for the actual wait depends on whether
+// _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK is defined. We might as well just test
+// both steady_clock and system_clock.
+template <typename Clock>
+void
+test_exclusive_relative(chrono::nanoseconds offset)
+{
+ std::shared_timed_mutex stm;
+ const auto d = -Clock::now().time_since_epoch() + offset;
+ VERIFY(stm.try_lock_for(d));
+ VERIFY(!stm.try_lock_for(d));
+}
+
+template <typename Clock>
+void
+test_shared_relative(chrono::nanoseconds offset)
+{
+ std::shared_timed_mutex stm;
+ const auto d = -Clock::now().time_since_epoch() + offset;
+ VERIFY(stm.try_lock_shared_for(d));
+ stm.unlock_shared();
+ // Should complete immediately
+ VERIFY(stm.try_lock_for(chrono::seconds{10}));
+ VERIFY(!stm.try_lock_shared_for(d));
+}
+
+int main()
+{
+ // Try once with an offset that ought to result in tv_sec == 0, tv_nsec < 0
+ // and one with an offset that ought to result in tv_sec < 0, tv_nsec == 0
+ // for the absolute calls at least. It's not really possible to arrange for
+ // the relative calls to have tv_nsec == 0 due to time advancing.
+ using namespace std::chrono_literals;
+ for (const chrono::nanoseconds offset : {
+ // tv_sec == 0, tv_nsec == 0
+ chrono::nanoseconds{0},
+ // tv_sec == 0, tv_nsec < 0
+ chrono::nanoseconds{-10ms},
+ // tv_sec < 0
+ chrono::nanoseconds{-10s}
+ }) {
+ test_exclusive_absolute<chrono::system_clock>(offset);
+ test_shared_absolute<chrono::system_clock>(offset);
+ test_exclusive_relative<chrono::system_clock>(offset);
+ test_shared_relative<chrono::system_clock>(offset);
+
+ test_exclusive_absolute<chrono::steady_clock>(offset);
+ test_shared_absolute<chrono::steady_clock>(offset);
+ test_exclusive_relative<chrono::steady_clock>(offset);
+ test_shared_relative<chrono::steady_clock>(offset);
+ }
+}
diff --git a/libstdc++-v3/testsuite/30_threads/this_thread/113327.cc b/libstdc++-v3/testsuite/30_threads/this_thread/113327.cc
new file mode 100644
index 0000000..2daa2b0
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/this_thread/113327.cc
@@ -0,0 +1,29 @@
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-gthreads "" }
+
+// PR libstdc++/113327
+// std::sleep_for(std::chrono::hours::max()) returns immediately
+
+#include <thread>
+#include <chrono>
+#include <cstdlib>
+#include <csignal>
+
+int main()
+{
+ std::thread sleepy([] {
+ // Rather than overflowing to a negative value, the timeout should be
+ // truncated to seconds::max() and so sleep for 292 billion years.
+ std::this_thread::sleep_for(std::chrono::minutes::max());
+ // This should not happen:
+ throw 1;
+ });
+ // Give the new thread a chance to start sleeping:
+ std::this_thread::yield();
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ // If we get here without the other thread throwing an exception
+ // then it should be sleeping peacefully, so the test passed.
+ // pthread_kill(sleepy.native_handle(), SIGINT);
+ std::_Exit(0);
+}
diff --git a/libstdc++-v3/testsuite/30_threads/this_thread/sleep_for.cc b/libstdc++-v3/testsuite/30_threads/this_thread/sleep_for.cc
index 3f55ccc..5b0518d 100644
--- a/libstdc++-v3/testsuite/30_threads/this_thread/sleep_for.cc
+++ b/libstdc++-v3/testsuite/30_threads/this_thread/sleep_for.cc
@@ -37,7 +37,20 @@ test01()
VERIFY( (chr::system_clock::now() - begin) >= ms );
}
+void
+test_negative()
+{
+ chr::system_clock::time_point begin = chr::system_clock::now();
+
+ std::this_thread::sleep_for(-chr::hours(8));
+
+ // That should have completed immediately, but be generous because we don't
+ // want spurious failures on busy machines.
+ VERIFY( (chr::system_clock::now() - begin) < chr::seconds(10) );
+}
+
int main()
{
test01();
+ test_negative();
}
diff --git a/libstdc++-v3/testsuite/30_threads/this_thread/sleep_until.cc b/libstdc++-v3/testsuite/30_threads/this_thread/sleep_until.cc
index 1fb82b6..8c70c2e 100644
--- a/libstdc++-v3/testsuite/30_threads/this_thread/sleep_until.cc
+++ b/libstdc++-v3/testsuite/30_threads/this_thread/sleep_until.cc
@@ -26,18 +26,36 @@
namespace chr = std::chrono;
+template <typename Clock>
void
test01()
{
- chr::system_clock::time_point begin = chr::system_clock::now();
+ typename Clock::time_point begin = Clock::now();
chr::microseconds ms(500);
- std::this_thread::sleep_until(chr::system_clock::now() + ms);
+ std::this_thread::sleep_until(Clock::now() + ms);
- VERIFY( (chr::system_clock::now() - begin) >= ms );
+ VERIFY( (Clock::now() - begin) >= ms );
+}
+
+template <typename Clock>
+void
+test_negative()
+{
+ typename Clock::time_point begin = Clock::now();
+
+ typename Clock::time_point tp(-chr::hours(8));
+ std::this_thread::sleep_until(tp);
+
+ // That should have completed immediately, but be generous because we don't
+ // want spurious failures on busy machines.
+ VERIFY( (Clock::now() - begin) < chr::seconds(10) );
}
int main()
{
- test01();
+ test01<chr::steady_clock>();
+ test01<chr::system_clock>();
+ test_negative<chr::steady_clock>();
+ test_negative<chr::system_clock>();
}
diff --git a/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/116586.cc b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/116586.cc
new file mode 100644
index 0000000..dcba7aa
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/116586.cc
@@ -0,0 +1,57 @@
+// { dg-do run { target c++11 } }
+
+#include <chrono>
+#include <mutex>
+#include <initializer_list>
+#include <testsuite_hooks.h>
+
+namespace chrono = std::chrono;
+
+// thread.timedmutex.requirements.general:
+// If abs_time has already passed, the function attempts to obtain
+// ownership without blocking (as if by calling try_lock()).
+
+template <typename Clock>
+void
+test_absolute(chrono::nanoseconds offset)
+{
+ std::timed_mutex mtx;
+ chrono::time_point<Clock> tp(offset);
+ VERIFY(mtx.try_lock_until(tp));
+ VERIFY(!mtx.try_lock_until(tp));
+}
+
+// The type of clock used for the actual wait depends on whether
+// _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK is defined. We might as well just test
+// both steady_clock and system_clock.
+template <typename Clock>
+void
+test_relative(chrono::nanoseconds offset)
+{
+ std::timed_mutex mtx;
+ const auto d = -Clock::now().time_since_epoch() + offset;
+ VERIFY(mtx.try_lock_for(d));
+ VERIFY(!mtx.try_lock_for(d));
+}
+
+int main()
+{
+ // Try once with an offset that ought to result in tv_sec == 0, tv_nsec < 0
+ // and one with an offset that ought to result in tv_sec < 0, tv_nsec == 0
+ // for the absolute calls at least. It's not really possible to arrange for
+ // the relative calls to have tv_nsec == 0 due to time advancing.
+ for (const chrono::nanoseconds offset : {
+ // tv_sec == 0, tv_nsec == 0
+ chrono::nanoseconds{0},
+ // tv_sec == 0, tv_nsec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::milliseconds{-10}),
+ // tv_sec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::seconds{-10})
+ }) {
+ test_absolute<chrono::system_clock>(offset);
+ test_relative<chrono::system_clock>(offset);
+
+ test_absolute<chrono::steady_clock>(offset);
+ test_relative<chrono::steady_clock>(offset);
+ }
+}
diff --git a/libstdc++-v3/testsuite/std/format/ranges/string.cc b/libstdc++-v3/testsuite/std/format/ranges/string.cc
index 99e5eaf..bef2cc7 100644
--- a/libstdc++-v3/testsuite/std/format/ranges/string.cc
+++ b/libstdc++-v3/testsuite/std/format/ranges/string.cc
@@ -279,6 +279,93 @@ void test_padding()
VERIFY( strip_prefix(resv, 46, '*') );
VERIFY( strip_quotes(resv) );
VERIFY( resv == in );
+
+ // width is 5, size is 15
+ in = "\u2160\u2161\u2162\u2163\u2164";
+ in += in; // width is 10, size is 30
+ in += in; // width is 20, size is 60
+ in += in; // width is 40, size is 120
+ in += in; // width is 80, size is 240
+ in += in; // width is 160, size is 480
+
+ lc.assign_range(in);
+
+ resv = res = std::format("{:s}", lc);
+ VERIFY( resv == in );
+
+ resv = res = std::format("{:*>10s}", lc);
+ VERIFY( resv == in );
+
+ resv = res = std::format("{:*>200s}", lc);
+ VERIFY( strip_prefix(resv, 40, '*') );
+ VERIFY( resv == in );
+
+ resv = res = std::format("{:?s}", lc);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == in );
+
+ resv = res = std::format("{:*>10?s}", lc);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == in );
+
+ resv = res = std::format("{:*>200?s}", lc);
+ VERIFY( strip_prefix(resv, 38, '*') );
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == in );
+}
+
+void test_escaping()
+{
+ std::string res;
+ std::string_view resv;
+
+ const std::string_view input =
+ "\t\n\r\\\""
+ "\u008a" // Cc, Control, Line Tabulation Set,
+ "\u00ad" // Cf, Format, Soft Hyphen
+ "\u1d3d" // Lm, Modifier letter, Modifier Letter Capital Ou
+ "\u00a0" // Zs, Space Separator, No-Break Space (NBSP)
+ "\u2029" // Zp, Paragraph Separator, Paragraph Separator
+ "\U0001f984" // So, Other Symbol, Unicorn Face
+ ;
+ const std::string_view output =
+ R"(\t\n\r\\\")"
+ R"(\u{8a})"
+ R"(\u{ad})"
+ "\u1d3d"
+ R"(\u{a0})"
+ R"(\u{2029})"
+ "\U0001f984";
+
+ std::forward_list<char> lc(std::from_range, input);
+ resv = res = std::format("{:s}", lc);
+ VERIFY( resv == input );
+ resv = res = std::format("{:?s}", lc);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == output );
+
+ // width is 5, size is 15
+ std::string in = "\u2160\u2161\u2162\u2163\u2164";
+ in += in; // width is 10, size is 30
+ in += in; // width is 20, size is 60
+ in += in; // width is 40, size is 120
+ in += in; // width is 80, size is 240
+ in += in; // width is 160, size is 480
+ std::string_view inv = in;
+
+ // last charcter is incomplete
+ lc.assign_range(inv.substr(0, 479));
+
+ // non-debug format, chars copied as is
+ resv = res = std::format("{:s}", lc);
+ VERIFY( resv == inv.substr(0, 479) );
+
+ // debug-format, incomplete code-point sequence is esaped
+ resv = res = std::format("{:?s}", lc);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv.substr(0, 477) == inv.substr(0, 477) );
+ resv.remove_prefix(477);
+ VERIFY( resv == R"(\x{e2}\x{85})" );
}
int main()
@@ -287,4 +374,6 @@ int main()
test_outputs<char>();
test_outputs<wchar_t>();
test_nested();
+ test_padding();
+ test_escaping();
}
diff --git a/libstdc++-v3/testsuite/std/time/month_day/io.cc b/libstdc++-v3/testsuite/std/time/month_day/io.cc
index 30aa588..c3ae180 100644
--- a/libstdc++-v3/testsuite/std/time/month_day/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month_day/io.cc
@@ -23,6 +23,45 @@ test_ostream()
}
void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%b%%%B%t%m%n %d%%%e}", month(1)/day(3));
+ VERIFY( s == "Jan%January\t01\n 03% 3" );
+ s = std::format(loc_fr, "{:L%b%%%B%t%m%n %d%%%e}", month(1)/day(3));
+ VERIFY( s == "janv.%janvier\t01\n 03% 3");
+
+ s = std::format("{0:%m/%d} {0}", month(10)/day(13));
+ VERIFY( s == "10/13 Oct/13" );
+ s = std::format("{0:%m/%d} {0}", month(13)/day(34));
+ VERIFY( s == "13/34 13 is not a valid month/34 is not a valid day" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "bBdehm";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto md = month(1)/day(10);
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(md));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
+void
test_parse()
{
using namespace std::chrono;
@@ -102,6 +141,6 @@ test_parse()
int main()
{
test_ostream();
- // TODO: test_format();
+ test_format();
test_parse();
}
diff --git a/libstdc++-v3/testsuite/std/time/month_day_last/io.cc b/libstdc++-v3/testsuite/std/time/month_day_last/io.cc
index d15192c..484a8d8 100644
--- a/libstdc++-v3/testsuite/std/time/month_day_last/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month_day_last/io.cc
@@ -22,8 +22,47 @@ test_ostream()
VERIFY( ss.str() == "juil./last" );
}
+void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%b%%%B%t%m%n}", month(3)/last);
+ VERIFY( s == "Mar%March\t03\n" );
+ s = std::format(loc_fr, "{:L%b%%%B%t%m%n}", month(3)/last);
+ VERIFY( s == "mars%mars\t03\n");
+
+ s = std::format("{0:%m/last} {0}", month(4)/last);
+ VERIFY( s == "04/last Apr/last" );
+ s = std::format("{0:%m/last} {0}", month(0)/last);
+ VERIFY( s == "00/last 0 is not a valid month/last" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "bBhm";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto mdl = month(1)/last;
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(mdl));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
int main()
{
test_ostream();
- // TODO: test_format();
+ test_format();
}
diff --git a/libstdc++-v3/testsuite/std/time/month_weekday/io.cc b/libstdc++-v3/testsuite/std/time/month_weekday/io.cc
index 1838030..0c2dcaf 100644
--- a/libstdc++-v3/testsuite/std/time/month_weekday/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month_weekday/io.cc
@@ -23,8 +23,47 @@ test_ostream()
VERIFY( ss.str() == "juil./jeu.[4]" );
}
+void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%b%%%B%t%m%n %a%%%A%t%u%n%w}", month(5)/weekday(1)[2]);
+ VERIFY( s == "May%May\t05\n Mon%Monday\t1\n1" );
+ s = std::format(loc_fr, "{:L%b%%%B%t%m%n %a%%%A%t%u%n%w}", month(5)/weekday(1)[2]);
+ VERIFY( s == "mai%mai\t05\n lun.%lundi\t1\n1");
+
+ s = std::format("{0:%m/%u[]} {0}", month(9)/weekday(0)[2]);
+ VERIFY( s == "09/7[] Sep/Sun[2]" );
+ s = std::format("{0:%m/%u[]} {0}", month(111)/weekday(8)[0]);
+ VERIFY( s == "111/8[] 111 is not a valid month/8 is not a valid weekday[0 is not a valid index]" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "aAbBhmuw";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto mwi = month(1)/weekday(1)[1];
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(mwi));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
int main()
{
test_ostream();
- // TODO: test_format();
+ test_format();
}
diff --git a/libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc b/libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc
index 6ba4d8a..2c29258 100644
--- a/libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc
@@ -23,8 +23,47 @@ test_ostream()
VERIFY( ss.str() == "juil./jeu.[last]" );
}
+void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%b%%%B%t%m%n %a%%%A%t%u%n%w}", month(6)/weekday(2)[last]);
+ VERIFY( s == "Jun%June\t06\n Tue%Tuesday\t2\n2" );
+ s = std::format(loc_fr, "{:L%b%%%B%t%m%n %a%%%A%t%u%n%w}", month(6)/weekday(2)[last]);
+ VERIFY( s == "juin%juin\t06\n mar.%mardi\t2\n2");
+
+ s = std::format("{0:%m/%w[last]} {0}", month(8)/weekday(7)[last]);
+ VERIFY( s == "08/0[last] Aug/Sun[last]" );
+ s = std::format("{0:%m/%w[last]} {0}", month(70)/weekday(9)[last]);
+ VERIFY( s == "70/9[last] 70 is not a valid month/9 is not a valid weekday[last]" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "aAbBhmuw";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto mwl = month(1)/weekday(1)[last];
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(mwl));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
int main()
{
test_ostream();
- // TODO: test_format();
+ test_format();
}
diff --git a/libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc b/libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc
index ca315de..ae86419 100644
--- a/libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc
+++ b/libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc
@@ -22,8 +22,47 @@ test_ostream()
VERIFY( ss.str() == "sam.[1]" );
}
+void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%a%%%A%t%u%n%w}", weekday(7)[3]);
+ VERIFY( s == "Sun%Sunday\t7\n0" );
+ s = std::format(loc_fr, "{:L%a%%%A%t%u%n%w}", weekday(7)[3]);
+ VERIFY( s == "dim.%dimanche\t7\n0");
+
+ s = std::format("{0:%w[]} {0}", weekday(4)[4]);
+ VERIFY( s == "4[] Thu[4]" );
+ s = std::format("{0:%w[]} {0}", weekday(10)[7]);
+ VERIFY( s == "10[] 10 is not a valid weekday[7 is not a valid index]" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "aAuw";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto wi = weekday(1)[1];
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(wi));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
int main()
{
test_ostream();
- // TODO: test_format();
+ test_format();
}
diff --git a/libstdc++-v3/testsuite/std/time/weekday_last/io.cc b/libstdc++-v3/testsuite/std/time/weekday_last/io.cc
index 3b64c65..49cf0d5 100644
--- a/libstdc++-v3/testsuite/std/time/weekday_last/io.cc
+++ b/libstdc++-v3/testsuite/std/time/weekday_last/io.cc
@@ -22,8 +22,47 @@ test_ostream()
VERIFY( ss.str() == "sam.[last]" );
}
+void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%a%%%A%t%u%n%w}", weekday(5)[last]);
+ VERIFY( s == "Fri%Friday\t5\n5" );
+ s = std::format(loc_fr, "{:L%a%%%A%t%u%n%w}", weekday(5)[last]);
+ VERIFY( s == "ven.%vendredi\t5\n5");
+
+ s = std::format("{0:%w[last]} {0}", weekday(6)[last]);
+ VERIFY( s == "6[last] Sat[last]" );
+ s = std::format("{0:%w[last]} {0}", weekday(9)[last]);
+ VERIFY( s == "9[last] 9 is not a valid weekday[last]" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "aAuw";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto wl = weekday(1)[last];
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(wl));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
int main()
{
test_ostream();
- // TODO: test_format();
+ test_format();
}
diff --git a/libstdc++-v3/testsuite/std/time/year_month/io.cc b/libstdc++-v3/testsuite/std/time/year_month/io.cc
index 7bb3442..3392eb3 100644
--- a/libstdc++-v3/testsuite/std/time/year_month/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year_month/io.cc
@@ -23,6 +23,45 @@ test_ostream()
}
void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%C%%%y\t%Y %b%%%B%t%m%n}", year(2019)/month(4));
+ VERIFY( s == "20%19\t2019 Apr%April\t04\n" );
+ s = std::format(loc_fr, "{:L%C%%%y\t%Y %b%%%B%t%m%n}", year(2019)/month(4));
+ VERIFY( s == "20%19\t2019 avril%avril\t04\n");
+
+ s = std::format("{0:%Y/%m} {0}", year(2018)/month(2));
+ VERIFY( s == "2018/02 2018/Feb" );
+ s = std::format("{0:%Y/%m} {0}", year(-32768)/month(15));
+ VERIFY( s == "-32768/15 -32768 is not a valid year/15 is not a valid month" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "CbBhmyY";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto ym = year(2013)/month(1);
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(ym));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
+void
test_parse()
{
using namespace std::chrono;
@@ -73,6 +112,6 @@ test_parse()
int main()
{
test_ostream();
- // TODO: test_format();
+ test_format();
test_parse();
}