diff options
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(); } |