diff --git a/README.md b/README.md index 0b3c8b3221e..6e48b4eb109 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ issue. The [bug tag][] and [enhancement tag][] are being populated. # Goals -We're implementing the latest C++ Working Draft, currently [N4928][], which will eventually become the next C++ +We're implementing the latest C++ Working Draft, currently [N4944][], which will eventually become the next C++ International Standard. The terms Working Draft (WD) and Working Paper (WP) are interchangeable; we often informally refer to these drafts as "the Standard" while being aware of the difference. (There are other relevant Standards; for example, supporting `/std:c++14` and `/std:c++17` involves understanding how the C++14 and C++17 @@ -532,7 +532,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception [LWG issues]: https://cplusplus.github.io/LWG/lwg-toc.html [LWG tag]: https://github.com/microsoft/STL/issues?q=is%3Aopen+is%3Aissue+label%3ALWG [Microsoft Open Source Code of Conduct]: https://opensource.microsoft.com/codeofconduct/ -[N4928]: https://wg21.link/n4928 +[N4944]: https://wg21.link/n4944 [NOTICE.txt]: NOTICE.txt [Ninja]: https://ninja-build.org [Pipelines]: https://dev.azure.com/vclibs/STL/_build/latest?definitionId=4&branchName=main diff --git a/stl/inc/__msvc_chrono.hpp b/stl/inc/__msvc_chrono.hpp index 4f4e5a1915e..1d0899f240f 100644 --- a/stl/inc/__msvc_chrono.hpp +++ b/stl/inc/__msvc_chrono.hpp @@ -695,10 +695,10 @@ namespace chrono { } // namespace chrono template -_NODISCARD bool _To_xtime_10_day_clamped(_CSTD xtime& _Xt, const _CHRONO duration<_Rep, _Period>& _Rel_time) noexcept( - is_arithmetic_v<_Rep>) { - // Convert duration to xtime, maximum 10 days from now, returns whether clamping occurred. - // If clamped, timeouts will be transformed into spurious non-timeout wakes, due to ABI restrictions where +_NODISCARD bool _To_timespec64_sys_10_day_clamped( + _timespec64& _Ts64, const _CHRONO duration<_Rep, _Period>& _Rel_time) noexcept(is_arithmetic_v<_Rep>) { + // Convert duration to _timespec64 representing system time, maximum 10 days from now, returns whether clamping + // occurred. If clamped, timeouts will be transformed into spurious non-timeout wakes, due to ABI restrictions where // the other side of the DLL boundary overflows int32_t milliseconds. // Every function calling this one is TRANSITION, ABI constexpr _CHRONO nanoseconds _Ten_days{_CHRONO hours{24} * 10}; @@ -712,9 +712,9 @@ _NODISCARD bool _To_xtime_10_day_clamped(_CSTD xtime& _Xt, const _CHRONO duratio } const auto _Whole_seconds = _CHRONO duration_cast<_CHRONO seconds>(_Tx0); - _Xt.sec = _Whole_seconds.count(); + _Ts64.tv_sec = _Whole_seconds.count(); _Tx0 -= _Whole_seconds; - _Xt.nsec = static_cast(_Tx0.count()); + _Ts64.tv_nsec = static_cast(_Tx0.count()); return _Clamped; } diff --git a/stl/inc/__msvc_tzdb.hpp b/stl/inc/__msvc_tzdb.hpp index 3948efa3e72..137f17d908c 100644 --- a/stl/inc/__msvc_tzdb.hpp +++ b/stl/inc/__msvc_tzdb.hpp @@ -66,6 +66,16 @@ struct __std_tzdb_sys_info { const char* _Abbrev; }; +enum class __std_tzdb_sys_info_type : char { + // TRANSITION, ABI: In order to be compatible with existing object files which do not know about + // `__std_tzdb_sys_info_type`, the type is passed in the after-end byte of a string passed with its length to + // `__std_tzdb_get_sys_info`. Since older object files always pass the `.c_str()` of a `std::string` + // to that function, the after-end byte will always be '\0'. + _Full = '\0', + _Offset_only, + _Offset_and_range, +}; + _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noexcept; void __stdcall __std_tzdb_delete_time_zones(__std_tzdb_time_zones_info* _Info) noexcept; diff --git a/stl/inc/chrono b/stl/inc/chrono index c81b284dbed..ce864da0181 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -1750,70 +1750,12 @@ namespace chrono { template _NODISCARD sys_info get_info(const sys_time<_Duration>& _Sys) const { - return _Get_info(_Sys.time_since_epoch()); + return _Get_info(_Sys.time_since_epoch(), __std_tzdb_sys_info_type::_Full); } template _NODISCARD local_info get_info(const local_time<_Duration>& _Local) const { - local_info _Info{}; - const auto _Time_since_ep = _Local.time_since_epoch(); - _Info.first = _Get_info(_Time_since_ep); - - const sys_seconds _Local_sys{_CHRONO duration_cast(_Time_since_ep)}; - const auto _Curr_sys = _Local_sys - _Info.first.offset; - if (_Info.first.begin != _Min_seconds && _Curr_sys < _Info.first.begin + days{1}) { - // get previous transition information - _Info.second = get_info(_Info.first.begin - seconds{1}); - - const auto _Transition = _Info.first.begin; - const auto _Prev_sys = _Local_sys - _Info.second.offset; - if (_Curr_sys >= _Transition) { - if (_Prev_sys < _Transition) { - _Info.result = local_info::ambiguous; - _STD swap(_Info.first, _Info.second); - } else { - _Info.result = local_info::unique; - _Info.second = {}; - } - } else { - if (_Prev_sys >= _Transition) { - _Info.result = local_info::nonexistent; - _STD swap(_Info.first, _Info.second); - } else { - _Info.result = local_info::unique; - _Info.first = _STD move(_Info.second); - _Info.second = {}; - } - } - } else if (_Info.first.end != _Max_seconds && _Curr_sys > _Info.first.end - days{1}) { - // get next transition information - _Info.second = get_info(_Info.first.end + seconds{1}); - - const auto _Transition = _Info.first.end; - const auto _Next_sys = _Local_sys - _Info.second.offset; - if (_Curr_sys < _Transition) { - if (_Next_sys >= _Transition) { - _Info.result = local_info::ambiguous; - } else { - _Info.result = local_info::unique; - _Info.second = {}; - } - } else { - if (_Next_sys < _Transition) { - _Info.result = local_info::nonexistent; - } else { - _Info.result = local_info::unique; - _Info.first = _STD move(_Info.second); - _Info.second = {}; - } - } - } else { - // local time is contained inside of first transition boundaries by at least 1 day - _Info.result = local_info::unique; - _Info.second = {}; - } - - return _Info; + return _Get_local_info(_Local, __std_tzdb_sys_info_type::_Full); } template @@ -1831,7 +1773,7 @@ namespace chrono { template _NODISCARD sys_time> to_sys( const local_time<_Duration>& _Local, const choose _Choose) const { - const auto _Info = get_info(_Local); + const auto _Info = _Get_local_info(_Local, __std_tzdb_sys_info_type::_Offset_and_range); if (_Info.result == local_info::nonexistent) { return _Info.first.end; } @@ -1844,7 +1786,7 @@ namespace chrono { template _NODISCARD local_time> to_local(const sys_time<_Duration>& _Sys) const { - const auto _Info = get_info(_Sys); + const auto _Info = _Get_info(_Sys.time_since_epoch(), __std_tzdb_sys_info_type::_Offset_only); return local_time>{_Sys.time_since_epoch() + _Info.offset}; } @@ -1853,11 +1795,20 @@ namespace chrono { private: template - _NODISCARD sys_info _Get_info(const _Duration& _Dur) const { + _NODISCARD sys_info _Get_info(const _Duration& _Dur, __std_tzdb_sys_info_type _Type) const { using _Internal_duration = duration<__std_tzdb_epoch_milli, milli>; const auto _Internal_dur = _CHRONO duration_cast<_Internal_duration>(_Dur); + + // TRANSITION, vNext + // Because the signature of __std_tzdb_get_sys_info cannot be changed, _Type is encoded in the + // time zone name. In vNext, this should be a dedicated argument. + const string _Tz_arg = _Name + static_cast(_Type); + + const auto _Tz_len = _Name.length(); + const unique_ptr<__std_tzdb_sys_info, _Tzdb_deleter<__std_tzdb_sys_info>> _Info{ - __std_tzdb_get_sys_info(_Name.c_str(), _Name.length(), _Internal_dur.count())}; + __std_tzdb_get_sys_info(_Tz_arg.c_str(), _Tz_len, _Internal_dur.count())}; + if (_Info == nullptr) { _Xbad_alloc(); } else if (_Info->_Err == __std_tzdb_error::_Win_error) { @@ -1882,7 +1833,71 @@ namespace chrono { .end = _End, .offset = _CHRONO duration_cast(_Internal_duration{_Info->_Offset}), .save = _CHRONO duration_cast(_Internal_duration{_Info->_Save}), - .abbrev = _Info->_Abbrev}; + .abbrev = _Info->_Abbrev ? _Info->_Abbrev : ""}; + } + + template + _NODISCARD local_info _Get_local_info( + const local_time<_Duration>& _Local, __std_tzdb_sys_info_type _Type) const { + local_info _Info{}; + const auto _Time_since_ep = _Local.time_since_epoch(); + _Info.first = _Get_info(_Time_since_ep, _Type); + + const sys_seconds _Local_sys{_CHRONO duration_cast(_Time_since_ep)}; + const auto _Curr_sys = _Local_sys - _Info.first.offset; + if (_Info.first.begin != _Min_seconds && _Curr_sys < _Info.first.begin + days{1}) { + // get previous transition information + _Info.second = _Get_info((_Info.first.begin - seconds{1}).time_since_epoch(), _Type); + + const auto _Transition = _Info.first.begin; + const auto _Prev_sys = _Local_sys - _Info.second.offset; + if (_Curr_sys >= _Transition) { + if (_Prev_sys < _Transition) { + _Info.result = local_info::ambiguous; + _STD swap(_Info.first, _Info.second); + } else { + _Info.result = local_info::unique; + _Info.second = {}; + } + } else { + if (_Prev_sys >= _Transition) { + _Info.result = local_info::nonexistent; + _STD swap(_Info.first, _Info.second); + } else { + _Info.result = local_info::unique; + _Info.first = _STD move(_Info.second); + _Info.second = {}; + } + } + } else if (_Info.first.end != _Max_seconds && _Curr_sys > _Info.first.end - days{1}) { + // get next transition information + _Info.second = _Get_info((_Info.first.end + seconds{1}).time_since_epoch(), _Type); + + const auto _Transition = _Info.first.end; + const auto _Next_sys = _Local_sys - _Info.second.offset; + if (_Curr_sys < _Transition) { + if (_Next_sys >= _Transition) { + _Info.result = local_info::ambiguous; + } else { + _Info.result = local_info::unique; + _Info.second = {}; + } + } else { + if (_Next_sys < _Transition) { + _Info.result = local_info::nonexistent; + } else { + _Info.result = local_info::unique; + _Info.first = _STD move(_Info.second); + _Info.second = {}; + } + } + } else { + // local time is contained inside of first transition boundaries by at least 1 day + _Info.result = local_info::unique; + _Info.second = {}; + } + + return _Info; } string _Name; @@ -2955,7 +2970,7 @@ namespace chrono { void_t()))))>> = true; template - _NODISCARD _CONSTEVAL _Clock_cast_strategy _Choose_clock_cast() noexcept { + _NODISCARD consteval _Clock_cast_strategy _Choose_clock_cast() noexcept { using _Tp = const time_point<_SourceClock, _Duration>&; if constexpr (is_invocable_v, _Tp>) { diff --git a/stl/inc/compare b/stl/inc/compare index 99e4a402cde..b556d805167 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -394,7 +394,7 @@ namespace _Strong_order { enum class _St { _None, _Adl, _Floating, _Three }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { if constexpr (!same_as, decay_t<_Ty2>>) { return {_St::_None}; } else if constexpr (_Has_ADL<_Ty1, _Ty2>) { @@ -497,7 +497,7 @@ namespace _Weak_order { enum class _St { _None, _Adl, _Floating, _Three, _Strong }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { if constexpr (!same_as, decay_t<_Ty2>>) { return {_St::_None}; } else if constexpr (_Has_ADL<_Ty1, _Ty2>) { @@ -626,7 +626,7 @@ namespace _Partial_order { enum class _St { _None, _Adl, _Three, _Weak, _Strong }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { if constexpr (!same_as, decay_t<_Ty2>>) { return {_St::_None}; } else if constexpr (_Has_ADL<_Ty1, _Ty2>) { @@ -695,7 +695,7 @@ namespace _Compare_strong_order_fallback { enum class _St { _None, _Strong, _Fallback }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { if constexpr (!same_as, decay_t<_Ty2>>) { return {_St::_None}; } else if constexpr (_Can_strong_order<_Ty1, _Ty2>) { @@ -745,7 +745,7 @@ namespace _Compare_weak_order_fallback { enum class _St { _None, _Weak, _Fallback }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { if constexpr (!same_as, decay_t<_Ty2>>) { return {_St::_None}; } else if constexpr (_Can_weak_order<_Ty1, _Ty2>) { @@ -802,7 +802,7 @@ namespace _Compare_partial_order_fallback { enum class _St { _None, _Partial, _Fallback }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { if constexpr (!same_as, decay_t<_Ty2>>) { return {_St::_None}; } else if constexpr (_Can_partial_order<_Ty1, _Ty2>) { diff --git a/stl/inc/condition_variable b/stl/inc/condition_variable index e5b917a87c0..6f67941c9df 100644 --- a/stl/inc/condition_variable +++ b/stl/inc/condition_variable @@ -122,10 +122,10 @@ public: } // TRANSITION, ABI: The standard says that we should use a steady clock, - // but unfortunately our ABI speaks struct xtime, which is relative to the system clock. - _CSTD xtime _Tgt; - const bool _Clamped = _To_xtime_10_day_clamped(_Tgt, _Rel_time); - const cv_status _Result = _Wait_until(_Lck, &_Tgt); + // but unfortunately our ABI relies on the system clock. + _timespec64 _Tgt; + const bool _Clamped = _To_timespec64_sys_10_day_clamped(_Tgt, _Rel_time); + const cv_status _Result = _Wait_until_sys_time(_Lck, &_Tgt); if (_Clamped) { return cv_status::no_timeout; } @@ -139,22 +139,6 @@ public: return wait_until(_Lck, _To_absolute_time(_Rel_time), _STD move(_Pred)); } - template - cv_status wait_until(_Lock& _Lck, const xtime* const _Abs_time) { // wait for signal with timeout - return _Wait_until(_Lck, _Abs_time); - } - - template - bool wait_until(_Lock& _Lck, const xtime* const _Abs_time, _Predicate _Pred) { - // wait for signal with timeout and check predicate - while (!_Pred()) { - if (_Wait_until(_Lck, _Abs_time) == cv_status::timeout) { - return _Pred(); - } - } - return true; - } - #if _HAS_CXX20 private: struct _Cv_any_notify_all { @@ -221,9 +205,9 @@ public: const auto _Rel_time = _Abs_time - _Now; // TRANSITION, ABI: The standard says that we should use a steady clock, - // but unfortunately our ABI speaks struct xtime, which is relative to the system clock. - _CSTD xtime _Tgt; - (void) _To_xtime_10_day_clamped(_Tgt, _Rel_time); + // but unfortunately our ABI relies on the system clock. + _timespec64 _Tgt; + (void) _To_timespec64_sys_10_day_clamped(_Tgt, _Rel_time); (void) _Cnd_timedwait(_Mycnd(), _Myptr->_Mymtx(), &_Tgt); _Guard_unlocks_before_locking_outer.unlock(); } // relock @@ -247,7 +231,8 @@ private: } template - cv_status _Wait_until(_Lock& _Lck, const xtime* const _Abs_time) { // wait for signal with timeout + cv_status _Wait_until_sys_time(_Lock& _Lck, const _timespec64* const _Abs_time) { + // wait for signal with timeout const shared_ptr _Ptr = _Myptr; // for immunity to *this destruction unique_lock _Guard{*_Ptr}; _Unlock_guard<_Lock> _Unlock_outer{_Lck}; diff --git a/stl/inc/expected b/stl/inc/expected index a0f05bd8eea..93fbfcf0843 100644 --- a/stl/inc/expected +++ b/stl/inc/expected @@ -238,14 +238,15 @@ public: // clang-format on template - static constexpr bool _Allow_unwrapping = !is_constructible_v<_Ty, expected<_Uty, _UErr>&> // - && !is_constructible_v<_Ty, expected<_Uty, _UErr>> // - && !is_constructible_v<_Ty, const expected<_Uty, _UErr>&> // - && !is_constructible_v<_Ty, const expected<_Uty, _UErr>> // - && !is_convertible_v&, _Ty> // - && !is_convertible_v&&, _Ty> // - && !is_convertible_v&, _Ty> // - && !is_convertible_v&&, _Ty> // + static constexpr bool _Allow_unwrapping = disjunction_v, bool>, + negation&>, // + is_constructible<_Ty, expected<_Uty, _UErr>>, // + is_constructible<_Ty, const expected<_Uty, _UErr>&>, // + is_constructible<_Ty, const expected<_Uty, _UErr>>, // + is_convertible&, _Ty>, // + is_convertible&&, _Ty>, // + is_convertible&, _Ty>, // + is_convertible&&, _Ty>>>> // && !is_constructible_v, expected<_Uty, _UErr>&> // && !is_constructible_v, expected<_Uty, _UErr>> // && !is_constructible_v, const expected<_Uty, _UErr>&> // @@ -280,7 +281,9 @@ public: template requires (!is_same_v, in_place_t> && !is_same_v, expected> - && !_Is_specialization_v, unexpected> && is_constructible_v<_Ty, _Uty>) + && !_Is_specialization_v, unexpected> + && (!is_same_v, bool> || !_Is_specialization_v, expected>) + && is_constructible_v<_Ty, _Uty>) constexpr explicit(!is_convertible_v<_Uty, _Ty>) expected(_Uty&& _Other) noexcept(is_nothrow_constructible_v<_Ty, _Uty>) // strengthened : _Value(_STD forward<_Uty>(_Other)), _Has_value(true) {} diff --git a/stl/inc/functional b/stl/inc/functional index 69954d4f9c6..f88728cca79 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -647,7 +647,8 @@ struct _Unforced { // tag to distinguish bind() from bind() // helper to give INVOKE an explicit return type; avoids undesirable Expression SFINAE template struct _Invoker_ret { // selected for all _Rx other than _Unforced - template + template ::template _Is_invocable_r<_Rx>::value, int> = 0> static _CONSTEXPR20 _Rx _Call(_Fx&& _Func, _Valtys&&... _Vals) noexcept(_Select_invoke_traits<_Fx, _Valtys...>::template _Is_nothrow_invocable_r<_Rx>::value) { // INVOKE, implicitly converted if constexpr (is_void_v<_Rx>) { @@ -760,7 +761,11 @@ private: } _Rx _Do_call(_Types&&... _Args) override { // call wrapped function - return _Invoker_ret<_Rx>::_Call(_Mypair._Myval2, _STD forward<_Types>(_Args)...); + if constexpr (is_void_v<_Rx>) { + (void) _STD invoke(_Mypair._Myval2, _STD forward<_Types>(_Args)...); + } else { + return _STD invoke(_Mypair._Myval2, _STD forward<_Types>(_Args)...); + } } const type_info& _Target_type() const noexcept override { @@ -817,7 +822,11 @@ private: } _Rx _Do_call(_Types&&... _Args) override { // call wrapped function - return _Invoker_ret<_Rx>::_Call(_Callee, _STD forward<_Types>(_Args)...); + if constexpr (is_void_v<_Rx>) { + (void) _STD invoke(_Callee, _STD forward<_Types>(_Args)...); + } else { + return _STD invoke(_Callee, _STD forward<_Types>(_Args)...); + } } const type_info& _Target_type() const noexcept override { @@ -1232,14 +1241,20 @@ template template _NODISCARD _Rx __stdcall _Function_inv_small(const _Move_only_function_data& _Self, _Types&&... _Args) noexcept(_Noex) { - return _Invoker_ret<_Rx>::_Call( - static_cast<_VtInvQuals>(*_Self._Small_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + if constexpr (is_void_v<_Rx>) { + (void) _STD invoke(static_cast<_VtInvQuals>(*_Self._Small_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + } else { + return _STD invoke(static_cast<_VtInvQuals>(*_Self._Small_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + } } template _NODISCARD _Rx __stdcall _Function_inv_large(const _Move_only_function_data& _Self, _Types&&... _Args) noexcept(_Noex) { - return _Invoker_ret<_Rx>::_Call( - static_cast<_VtInvQuals>(*_Self._Large_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + if constexpr (is_void_v<_Rx>) { + (void) _STD invoke(static_cast<_VtInvQuals>(*_Self._Large_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + } else { + return _STD invoke(static_cast<_VtInvQuals>(*_Self._Large_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + } } template @@ -1910,7 +1925,8 @@ struct _Select_fixer<_Cv_TiD, true, false, 0> { // reference_wrapper fixer template struct _Select_fixer<_Cv_TiD, false, true, 0> { // nested bind fixer - template + template )>...>, int> = 0> static constexpr auto _Apply(_Cv_TiD& _Tid, _Untuple&& _Ut, index_sequence<_Jx...>) noexcept( noexcept(_Tid(_STD get<_Jx>(_STD move(_Ut))...))) -> decltype(_Tid(_STD get<_Jx>(_STD move(_Ut))...)) { // call a nested bind expression @@ -1939,7 +1955,7 @@ template struct _Select_fixer<_Cv_TiD, false, false, _Jx> { // placeholder fixer static_assert(_Jx > 0, "invalid is_placeholder value"); - template + template ), int> = 0> static constexpr auto _Fix(_Cv_TiD&, _Untuple&& _Ut) noexcept -> decltype(_STD get<_Jx - 1>(_STD move(_Ut))) { // choose the Jth unbound argument (1-based indexing) return _STD get<_Jx - 1>(_STD move(_Ut)); @@ -1956,10 +1972,10 @@ constexpr auto _Fix_arg(_Cv_TiD& _Tid, _Untuple&& _Ut) noexcept( template _CONSTEXPR20 auto _Call_binder(_Invoker_ret<_Ret>, index_sequence<_Ix...>, _Cv_FD& _Obj, _Cv_tuple_TiD& _Tpl, _Untuple&& _Ut) noexcept(noexcept(_Invoker_ret<_Ret>::_Call(_Obj, - _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...))) - -> decltype(_Invoker_ret<_Ret>::_Call(_Obj, _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...)) { + _STD _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...))) + -> decltype(_Invoker_ret<_Ret>::_Call(_Obj, _STD _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...)) { // bind() and bind() invocation - return _Invoker_ret<_Ret>::_Call(_Obj, _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...); + return _Invoker_ret<_Ret>::_Call(_Obj, _STD _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...); } template diff --git a/stl/inc/iterator b/stl/inc/iterator index 35c85717aad..6884d506bd5 100644 --- a/stl/inc/iterator +++ b/stl/inc/iterator @@ -585,10 +585,10 @@ public: // clang-format on switch (_That._Contains) { case _Variantish_state::_Holds_first: - _Construct_in_place(_First, _That._First); + _STD _Construct_in_place(_First, _That._Get_first()); break; case _Variantish_state::_Holds_second: - _Construct_in_place(_Second, _That._Second); + _STD _Construct_in_place(_Second, _That._Get_second()); break; case _Variantish_state::_Nothing: break; @@ -605,10 +605,10 @@ public: : _Contains{_That._Contains} { switch (_Contains) { case _Variantish_state::_Holds_first: - _Construct_in_place(_First, _That._First); + _STD _Construct_in_place(_First, _That._Get_first()); break; case _Variantish_state::_Holds_second: - _Construct_in_place(_Second, _That._Second); + _STD _Construct_in_place(_Second, _That._Get_second()); break; case _Variantish_state::_Nothing: break; @@ -625,10 +625,10 @@ public: : _Contains{_That._Contains} { switch (_Contains) { case _Variantish_state::_Holds_first: - _Construct_in_place(_First, _STD move(_That._First)); + _STD _Construct_in_place(_First, _STD move(_That._Get_first())); break; case _Variantish_state::_Holds_second: - _Construct_in_place(_Second, _STD move(_That._Second)); + _STD _Construct_in_place(_Second, _STD move(_That._Get_second())); break; case _Variantish_state::_Nothing: break; @@ -656,10 +656,10 @@ public: if (_Contains == _That._Contains) { switch (_Contains) { case _Variantish_state::_Holds_first: - _First = _That._First; + _Get_first() = _That._Get_first(); break; case _Variantish_state::_Holds_second: - _Second = _That._Second; + _Get_second() = _That._Get_second(); break; case _Variantish_state::_Nothing: break; @@ -672,10 +672,10 @@ public: switch (_That._Contains) { case _Variantish_state::_Holds_first: - _Construct_in_place(_First, _That._First); + _STD _Construct_in_place(_First, _That._Get_first()); break; case _Variantish_state::_Holds_second: - _Construct_in_place(_Second, _That._Second); + _STD _Construct_in_place(_Second, _That._Get_second()); break; case _Variantish_state::_Nothing: break; @@ -701,10 +701,10 @@ public: if (_Contains == _That._Contains) { switch (_Contains) { case _Variantish_state::_Holds_first: - _First = _STD move(_That._First); + _Get_first() = _STD move(_That._Get_first()); break; case _Variantish_state::_Holds_second: - _Second = _STD move(_That._Second); + _Get_second() = _STD move(_That._Get_second()); break; case _Variantish_state::_Nothing: break; @@ -717,10 +717,10 @@ public: switch (_That._Contains) { case _Variantish_state::_Holds_first: - _Construct_in_place(_First, _STD move(_That._First)); + _STD _Construct_in_place(_First, _STD move(_That._Get_first())); break; case _Variantish_state::_Holds_second: - _Construct_in_place(_Second, _STD move(_That._Second)); + _STD _Construct_in_place(_Second, _STD move(_That._Get_second())); break; case _Variantish_state::_Nothing: break; @@ -741,10 +741,10 @@ public: if (_Contains == _That._Contains) { switch (_Contains) { case _Variantish_state::_Holds_first: - _First = _That._First; + _Get_first() = _That._Get_first(); break; case _Variantish_state::_Holds_second: - _Second = _That._Second; + _Get_second() = _That._Get_second(); break; case _Variantish_state::_Nothing: break; @@ -757,10 +757,10 @@ public: switch (_That._Contains) { case _Variantish_state::_Holds_first: - _Construct_in_place(_First, _That._First); + _STD _Construct_in_place(_First, _That._Get_first()); break; case _Variantish_state::_Holds_second: - _Construct_in_place(_Second, _That._Second); + _STD _Construct_in_place(_Second, _That._Get_second()); break; case _Variantish_state::_Nothing: break; @@ -780,10 +780,10 @@ public: if (_Left._Contains == _Right._Contains) { switch (_Left._Contains) { case _Variantish_state::_Holds_first: - _RANGES swap(_Left._First, _Right._First); + _RANGES swap(_Left._Get_first(), _Right._Get_first()); break; case _Variantish_state::_Holds_second: - _RANGES swap(_Left._Second, _Right._Second); + _RANGES swap(_Left._Get_second(), _Right._Get_second()); break; case _Variantish_state::_Nothing: break; @@ -810,6 +810,20 @@ public: } } + _NODISCARD constexpr _Ty1& _Get_first() noexcept { + return _First; + } + _NODISCARD constexpr const _Ty1& _Get_first() const noexcept { + return _First; + } + + _NODISCARD constexpr _Ty2& _Get_second() noexcept { + return _Second; + } + _NODISCARD constexpr const _Ty2& _Get_second() const noexcept { + return _Second; + } + constexpr void _Clear() noexcept { _Raw_clear(); _Contains = _Variantish_state::_Nothing; @@ -819,7 +833,7 @@ public: constexpr void _Emplace_first(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty1, _Types...>) { _Clear(); - _Construct_in_place(_First, _STD forward<_Types>(_Args)...); + _STD _Construct_in_place(_First, _STD forward<_Types>(_Args)...); _Contains = _Variantish_state::_Holds_first; } @@ -827,13 +841,13 @@ public: constexpr void _Emplace_second(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty2, _Types...>) { _Clear(); - _Construct_in_place(_Second, _STD forward<_Types>(_Args)...); + _STD _Construct_in_place(_Second, _STD forward<_Types>(_Args)...); _Contains = _Variantish_state::_Holds_second; } union { - _Ty1 _First; - _Ty2 _Second; + remove_cv_t<_Ty1> _First; + remove_cv_t<_Ty2> _Second; }; _Variantish_state _Contains; @@ -896,7 +910,7 @@ public: _STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_first, "common_iterator can only be dereferenced if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 - return *_Val._First; + return *_Val._Get_first(); } _NODISCARD constexpr decltype(auto) operator*() const @@ -906,7 +920,7 @@ public: _STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_first, "common_iterator can only be dereferenced if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 - return *_Val._First; + return *_Val._Get_first(); } // clang-format off @@ -920,9 +934,9 @@ public: "common_iterator can only be dereferenced if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 if constexpr (_Has_member_arrow || is_pointer_v<_Iter>) { - return _Val._First; + return _Val._Get_first(); } else if constexpr (is_reference_v>) { - auto&& _Tmp = *_Val._First; + auto&& _Tmp = *_Val._Get_first(); return _STD addressof(_Tmp); } else { class _Arrow_proxy : private _Proxy_base { @@ -936,7 +950,7 @@ public: } }; - return _Arrow_proxy{*_Val._First}; + return _Arrow_proxy{*_Val._Get_first()}; } } @@ -945,7 +959,7 @@ public: _STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_first, "common_iterator can only be incremented if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 - ++_Val._First; + ++_Val._Get_first(); return *this; } @@ -956,7 +970,7 @@ public: #endif // _ITERATOR_DEBUG_LEVEL != 0 if constexpr (forward_iterator<_Iter>) { common_iterator _Tmp = *this; - ++_Val._First; + ++_Val._Get_first(); return _Tmp; } else if constexpr (_Use_postfix_proxy<_Iter>) { class _Postfix_proxy : private _Proxy_base { @@ -970,11 +984,11 @@ public: } }; - _Postfix_proxy _Tmp{*_Val._First}; - ++_Val._First; + _Postfix_proxy _Tmp{*_Val._Get_first()}; + ++_Val._Get_first(); return _Tmp; } else { - return _Val._First++; + return _Val._Get_first()++; } } @@ -992,16 +1006,16 @@ public: if (_Left._Val._Contains == _Variantish_state::_Holds_first) { if (_Right_val._Contains == _Variantish_state::_Holds_first) { if constexpr (equality_comparable_with<_Iter, _OIter>) { - return _Left._Val._First == _Right_val._First; + return _Left._Val._Get_first() == _Right_val._Get_first(); } else { return true; } } else { - return _Left._Val._First == _Right_val._Second; + return _Left._Val._Get_first() == _Right_val._Get_second(); } } else { if (_Right_val._Contains == _Variantish_state::_Holds_first) { - return _Left._Val._Second == _Right_val._First; + return _Left._Val._Get_second() == _Right_val._Get_first(); } else { return true; } @@ -1021,13 +1035,13 @@ public: if (_Left._Val._Contains == _Variantish_state::_Holds_first) { if (_Right_val._Contains == _Variantish_state::_Holds_first) { - return _Left._Val._First - _Right_val._First; + return _Left._Val._Get_first() - _Right_val._Get_first(); } else { - return _Left._Val._First - _Right_val._Second; + return _Left._Val._Get_first() - _Right_val._Get_second(); } } else { if (_Right_val._Contains == _Variantish_state::_Holds_first) { - return _Left._Val._Second - _Right_val._First; + return _Left._Val._Get_second() - _Right_val._Get_first(); } else { return 0; } @@ -1035,26 +1049,26 @@ public: } _NODISCARD_FRIEND constexpr iter_rvalue_reference_t<_Iter> iter_move(const common_iterator& _Right) noexcept( - noexcept(_RANGES iter_move(_Right._Val._First))) + noexcept(_RANGES iter_move(_Right._Val._Get_first()))) requires input_iterator<_Iter> { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Right._Val._Contains == _Variantish_state::_Holds_first, "can only iter_move from common_iterator if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 - return _RANGES iter_move(_Right._Val._First); + return _RANGES iter_move(_Right._Val._Get_first()); } template _OIter, class _OSe> friend constexpr void iter_swap(const common_iterator& _Left, const common_iterator<_OIter, _OSe>& _Right) noexcept( - noexcept(_RANGES iter_swap(_Left._Val._First, _Right._Get_val()._First))) { + noexcept(_RANGES iter_swap(_Left._Val._Get_first(), _Right._Get_val()._Get_first()))) { auto& _Right_val = _Right._Get_val(); #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left._Val._Contains == _Variantish_state::_Holds_first && _Right_val._Contains == _Variantish_state::_Holds_first, "can only iter_swap common_iterators if both hold iterators"); #endif // _ITERATOR_DEBUG_LEVEL != 0 - return _RANGES iter_swap(_Left._Val._First, _Right_val._First); + return _RANGES iter_swap(_Left._Val._Get_first(), _Right_val._Get_first()); } _NODISCARD constexpr _Variantish<_Iter, _Se>& _Get_val() noexcept { diff --git a/stl/inc/memory b/stl/inc/memory index a0cdd884d7b..9ba2b098c14 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -530,15 +530,14 @@ namespace ranges { // clang-format off template - requires requires(void* _Void_ptr, _Types&&... _Args) { - ::new (_Void_ptr) _Ty(static_cast<_Types&&>(_Args)...); + requires requires(_Ty* _Ptr, _Types&&... _Args) { + ::new (static_cast(_Ptr)) _Ty(static_cast<_Types&&>(_Args)...); // per LWG-3888 } constexpr _Ty* operator()(_Ty* _Location, _Types&&... _Args) const - noexcept(noexcept(::new (const_cast(static_cast(_Location))) + noexcept(noexcept(::new (static_cast(_Location)) _Ty(_STD forward<_Types>(_Args)...))) /* strengthened */ { // clang-format on - _MSVC_CONSTEXPR return ::new (const_cast(static_cast(_Location))) - _Ty(_STD forward<_Types>(_Args)...); + _MSVC_CONSTEXPR return ::new (static_cast(_Location)) _Ty(_STD forward<_Types>(_Args)...); } }; @@ -935,6 +934,17 @@ namespace ranges { #endif // __cpp_lib_concepts #endif // _HAS_CXX17 +#if _HAS_CXX20 +template +_NODISCARD void* _Voidify_unfancy(_PtrTy _Ptr) noexcept { + if constexpr (is_pointer_v<_PtrTy>) { + return _Ptr; + } else { + return _STD addressof(*_Ptr); + } +} +#endif // _HAS_CXX20 + #if _HAS_DEPRECATED_RAW_STORAGE_ITERATOR _EXPORT_STD template class _CXX17_DEPRECATE_RAW_STORAGE_ITERATOR raw_storage_iterator { // wrap stores to raw buffer as output iterator @@ -956,12 +966,12 @@ public: } raw_storage_iterator& operator=(const _Ty& _Val) { // construct value designated by stored iterator - _Construct_in_place(*_Next, _Val); + _STD _Construct_in_place(const_cast<_Remove_cvref_t&>(*_Next), _Val); return *this; } raw_storage_iterator& operator=(_Ty&& _Val) { // construct value designated by stored iterator - _Construct_in_place(*_Next, _STD move(_Val)); + _STD _Construct_in_place(const_cast<_Remove_cvref_t&>(*_Next), _STD move(_Val)); return *this; } @@ -2081,12 +2091,12 @@ public: explicit _Ref_count_obj2(_Types&&... _Args) : _Ref_count_base() { #if _HAS_CXX20 if constexpr (sizeof...(_Types) == 1 && (is_same_v<_For_overwrite_tag, remove_cvref_t<_Types>> && ...)) { - _Default_construct_in_place(_Storage._Value); + _STD _Default_construct_in_place(_Storage._Value); ((void) _Args, ...); } else #endif // _HAS_CXX20 { - _Construct_in_place(_Storage._Value, _STD forward<_Types>(_Args)...); + _STD _Construct_in_place(_Storage._Value, _STD forward<_Types>(_Args)...); } } @@ -2099,7 +2109,7 @@ public: } union { - _Wrap<_Ty> _Storage; + _Wrap> _Storage; }; private: @@ -2201,12 +2211,12 @@ struct _NODISCARD _Uninitialized_rev_destroying_backout { template void _Emplace_back(_Types&&... _Vals) { // construct a new element at *_Last and increment - _Construct_in_place(*_Last, _STD forward<_Types>(_Vals)...); + _STD _Construct_in_place(*_Last, _STD forward<_Types>(_Vals)...); ++_Last; } void _Emplace_back_for_overwrite() { - _Default_construct_in_place(*_Last); + _STD _Default_construct_in_place(*_Last); ++_Last; } @@ -2350,7 +2360,7 @@ public: private: union { - _Wrap<_Element_type> _Storage; // flexible array must be last member + _Wrap> _Storage; // flexible array must be last member }; ~_Ref_count_unbounded_array() noexcept override { // TRANSITION, should be non-virtual @@ -2398,7 +2408,7 @@ private: size_t _Size; union { - _Wrap<_Element_type> _Storage; // flexible array must be last member + _Wrap> _Storage; // flexible array must be last member }; ~_Ref_count_unbounded_array() noexcept override { // TRANSITION, should be non-virtual @@ -2435,7 +2445,7 @@ public: } union { - _Wrap<_Ty> _Storage; + _Wrap> _Storage; }; private: @@ -2927,10 +2937,10 @@ _NODISCARD_SMART_PTR_ALLOC enable_if_t, shared_ptr<_Ty>> _Alblock _Rebound(_Al); _Alloc_construct_ptr _Constructor{_Rebound}; _Constructor._Allocate(); - ::new (_Voidify_iter(_Constructor._Ptr)) _Refc(_Al); + ::new (_STD _Voidify_unfancy(_Constructor._Ptr)) _Refc(_Al); shared_ptr<_Ty> _Ret; const auto _Ptr = static_cast*>(_Constructor._Ptr->_Storage._Value); - _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); + _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _STD _Unfancy(_Constructor._Release())); return _Ret; } @@ -2943,10 +2953,10 @@ _NODISCARD_SMART_PTR_ALLOC enable_if_t, shared_ptr<_Ty>> _Alblock _Rebound(_Al); _Alloc_construct_ptr _Constructor{_Rebound}; _Constructor._Allocate(); - ::new (_Voidify_iter(_Constructor._Ptr)) _Refc(_Al, _Val); + ::new (_STD _Voidify_unfancy(_Constructor._Ptr)) _Refc(_Al, _Val); shared_ptr<_Ty> _Ret; const auto _Ptr = static_cast*>(_Constructor._Ptr->_Storage._Value); - _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); + _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _STD _Unfancy(_Constructor._Release())); return _Ret; } @@ -2961,9 +2971,9 @@ _NODISCARD_SMART_PTR_ALLOC enable_if_t, shared_ptr<_T _Alblock _Rebound(_Al); _Alloc_construct_ptr _Constructor{_Rebound}; _Constructor._Allocate(); - ::new (_Voidify_iter(_Constructor._Ptr)) _Refc(_Al, _For_overwrite_tag{}); + ::new (_STD _Voidify_unfancy(_Constructor._Ptr)) _Refc(_Al, _For_overwrite_tag{}); const auto _Ptr = static_cast*>(_Constructor._Ptr->_Storage._Value); - _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); + _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _STD _Unfancy(_Constructor._Release())); } else { // make a shared_ptr to non-array object using _Refoa = _Ref_count_obj_alloc3, _Alloc>; @@ -2971,9 +2981,9 @@ _NODISCARD_SMART_PTR_ALLOC enable_if_t, shared_ptr<_T _Alblock _Rebound(_Al); _Alloc_construct_ptr<_Alblock> _Constructor{_Rebound}; _Constructor._Allocate(); - _Construct_in_place(*_Constructor._Ptr, _Al, _For_overwrite_tag{}); + _STD _Construct_in_place(*_Constructor._Ptr, _Al, _For_overwrite_tag{}); const auto _Ptr = reinterpret_cast<_Ty*>(_STD addressof(_Constructor._Ptr->_Storage._Value)); - _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); + _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _STD _Unfancy(_Constructor._Release())); } return _Ret; diff --git a/stl/inc/mutex b/stl/inc/mutex index 393d9dff2c5..b42019a59a1 100644 --- a/stl/inc/mutex +++ b/stl/inc/mutex @@ -202,11 +202,6 @@ public: #endif // _HAS_CXX20 } - _NODISCARD_CTOR_LOCK unique_lock(_Mutex& _Mtx, const xtime* _Abs_time) - : _Pmtx(_STD addressof(_Mtx)), _Owns(false) { // try to lock until _Abs_time - _Owns = _Pmtx->try_lock_until(_Abs_time); - } - _NODISCARD_CTOR_LOCK unique_lock(unique_lock&& _Other) noexcept : _Pmtx(_Other._Pmtx), _Owns(_Other._Owns) { _Other._Pmtx = nullptr; _Other._Owns = false; @@ -264,12 +259,6 @@ public: return _Owns; } - _NODISCARD_TRY_CHANGE_STATE bool try_lock_until(const xtime* _Abs_time) { - _Validate(); - _Owns = _Pmtx->try_lock_until(_Abs_time); - return _Owns; - } - void unlock() { if (!_Pmtx || !_Owns) { _Throw_system_error(errc::operation_not_permitted); @@ -690,10 +679,10 @@ public: } // TRANSITION, ABI: The standard says that we should use a steady clock, - // but unfortunately our ABI speaks struct xtime, which is relative to the system clock. - _CSTD xtime _Tgt; - const bool _Clamped = _To_xtime_10_day_clamped(_Tgt, _Rel_time); - const cv_status _Result = wait_until(_Lck, &_Tgt); + // but unfortunately our ABI relies on the system clock. + _timespec64 _Tgt; + const bool _Clamped = _To_timespec64_sys_10_day_clamped(_Tgt, _Rel_time); + const cv_status _Result = _Wait_until_sys_time(_Lck, &_Tgt); if (_Clamped) { return cv_status::no_timeout; } @@ -719,9 +708,9 @@ public: return cv_status::timeout; } - _CSTD xtime _Tgt; - (void) _To_xtime_10_day_clamped(_Tgt, _Abs_time - _Now); - const cv_status _Result = wait_until(_Lck, &_Tgt); + _timespec64 _Tgt; + (void) _To_timespec64_sys_10_day_clamped(_Tgt, _Abs_time - _Now); + const cv_status _Result = _Wait_until_sys_time(_Lck, &_Tgt); if (_Result == cv_status::no_timeout) { return cv_status::no_timeout; } @@ -738,28 +727,6 @@ public: return _Wait_until1(_Lck, _Abs_time, _Pred); } - cv_status wait_until(unique_lock& _Lck, const xtime* _Abs_time) { - // wait for signal with timeout - if (!_Mtx_current_owns(_Lck.mutex()->_Mymtx())) { - _Throw_Cpp_error(_OPERATION_NOT_PERMITTED); - } - - // Nothing to do to comply with LWG-2135 because std::mutex lock/unlock are nothrow - const int _Res = _Cnd_timedwait(_Mycnd(), _Lck.mutex()->_Mymtx(), _Abs_time); - - if (_Res == _Thrd_success) { - return cv_status::no_timeout; - } else { - return cv_status::timeout; - } - } - - template - bool wait_until(unique_lock& _Lck, const xtime* _Abs_time, _Predicate _Pred) { - // wait for signal with timeout and check predicate - return _Wait_until1(_Lck, _Abs_time, _Pred); - } - _NODISCARD native_handle_type native_handle() noexcept /* strengthened */ { return _Mycnd(); } @@ -779,11 +746,27 @@ private: return reinterpret_cast<_Cnd_t>(&_Cnd_storage); } + cv_status _Wait_until_sys_time(unique_lock& _Lck, const _timespec64* _Abs_time) { + // wait for signal with timeout + if (!_Mtx_current_owns(_Lck.mutex()->_Mymtx())) { + _Throw_Cpp_error(_OPERATION_NOT_PERMITTED); + } + + // Nothing to do to comply with LWG-2135 because std::mutex lock/unlock are nothrow + const int _Res = _Cnd_timedwait(_Mycnd(), _Lck.mutex()->_Mymtx(), _Abs_time); + + if (_Res == _Thrd_success) { + return cv_status::no_timeout; + } else { + return cv_status::timeout; + } + } + template - bool _Wait_until1(unique_lock& _Lck, const xtime* _Abs_time, _Predicate& _Pred) { + bool _Wait_until1(unique_lock& _Lck, const _timespec64* _Abs_time, _Predicate& _Pred) { // wait for signal with timeout and check predicate while (!_Pred()) { - if (wait_until(_Lck, _Abs_time) == cv_status::timeout) { + if (_Wait_until_sys_time(_Lck, _Abs_time) == cv_status::timeout) { return _Pred(); } } @@ -800,9 +783,9 @@ private: return false; } - _CSTD xtime _Tgt; - const bool _Clamped = _To_xtime_10_day_clamped(_Tgt, _Abs_time - _Now); - if (wait_until(_Lck, &_Tgt) == cv_status::timeout && !_Clamped) { + _timespec64 _Tgt; + const bool _Clamped = _To_timespec64_sys_10_day_clamped(_Tgt, _Abs_time - _Now); + if (_Wait_until_sys_time(_Lck, &_Tgt) == cv_status::timeout && !_Clamped) { return _Pred(); } } @@ -880,10 +863,6 @@ public: return _Try_lock_until(_Abs_time); } - _NODISCARD_TRY_CHANGE_STATE bool try_lock_until(const xtime* _Abs_time) { // try to lock the mutex with timeout - return _Try_lock_until(_Abs_time); - } - private: mutex _My_mutex; condition_variable _My_cond; @@ -997,10 +976,6 @@ public: return _Try_lock_until(_Abs_time); } - _NODISCARD_TRY_CHANGE_STATE bool try_lock_until(const xtime* _Abs_time) { // try to lock the mutex with timeout - return _Try_lock_until(_Abs_time); - } - private: mutex _My_mutex; condition_variable _My_cond; diff --git a/stl/inc/optional b/stl/inc/optional index a86eaa23be7..a9a4ee02945 100644 --- a/stl/inc/optional +++ b/stl/inc/optional @@ -71,7 +71,7 @@ template > struct _Optional_destruct_base { // either contains a value of _Ty or is empty (trivial destructor) union { _Nontrivial_dummy_type _Dummy; - remove_const_t<_Ty> _Value; + remove_cv_t<_Ty> _Value; }; bool _Has_value; @@ -98,7 +98,7 @@ template struct _Optional_destruct_base<_Ty, false> { // either contains a value of _Ty or is empty (non-trivial destructor) union { _Nontrivial_dummy_type _Dummy; - remove_const_t<_Ty> _Value; + remove_cv_t<_Ty> _Value; }; bool _Has_value; @@ -154,7 +154,7 @@ struct _Optional_construct_base : _Optional_destruct_base<_Ty> { is_nothrow_assignable_v<_Ty&, _Ty2>&& is_nothrow_constructible_v<_Ty, _Ty2>) { // assign / initialize the contained value from _Right if (this->_Has_value) { - this->_Value = _STD forward<_Ty2>(_Right); + static_cast<_Ty&>(this->_Value) = _STD forward<_Ty2>(_Right); } else { _Construct(_STD forward<_Ty2>(_Right)); } @@ -239,7 +239,9 @@ public: template using _AllowDirectConversion = bool_constant, optional>>, - negation, in_place_t>>, is_constructible<_Ty, _Ty2>>>; + negation, in_place_t>>, + negation, bool>, _Is_specialization<_Remove_cvref_t<_Ty2>, optional>>>, + is_constructible<_Ty, _Ty2>>>; template ::value, int> = 0> constexpr explicit(!is_convertible_v<_Ty2, _Ty>) @@ -247,11 +249,13 @@ public: : _Mybase(in_place, _STD forward<_Ty2>(_Right)) {} template - struct _AllowUnwrapping : bool_constant, is_constructible<_Ty, optional<_Ty2>&>, - is_constructible<_Ty, const optional<_Ty2>&>, - is_constructible<_Ty, const optional<_Ty2>>, is_constructible<_Ty, optional<_Ty2>>, - is_convertible&, _Ty>, is_convertible&, _Ty>, - is_convertible, _Ty>, is_convertible, _Ty>>> {}; + struct _AllowUnwrapping + : bool_constant, bool>, + negation, is_constructible<_Ty, optional<_Ty2>&>, + is_constructible<_Ty, const optional<_Ty2>&>, is_constructible<_Ty, const optional<_Ty2>>, + is_constructible<_Ty, optional<_Ty2>>, is_convertible&, _Ty>, + is_convertible&, _Ty>, is_convertible, _Ty>, + is_convertible, _Ty>>>>> {}; template , is_constructible<_Ty, const _Ty2&>>, int> = 0> @@ -425,7 +429,7 @@ public: "optional::value_or(U) requires U to be convertible to T (N4828 [optional.observe]/18)."); if (this->_Has_value) { - return this->_Value; + return static_cast(this->_Value); } return static_cast>(_STD forward<_Ty2>(_Right)); @@ -439,7 +443,7 @@ public: "optional::value_or(U) requires U to be convertible to T (N4828 [optional.observe]/20)."); if (this->_Has_value) { - return _STD move(this->_Value); + return static_cast<_Ty&&>(this->_Value); } return static_cast>(_STD forward<_Ty2>(_Right)); @@ -455,7 +459,7 @@ public: "(N4901 [optional.monadic]/2)."); if (this->_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), this->_Value); + return _STD invoke(_STD forward<_Fn>(_Func), static_cast<_Ty&>(this->_Value)); } else { return remove_cvref_t<_Uty>{}; } @@ -470,7 +474,7 @@ public: "(N4901 [optional.monadic]/2)."); if (this->_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), this->_Value); + return _STD invoke(_STD forward<_Fn>(_Func), static_cast(this->_Value)); } else { return remove_cvref_t<_Uty>{}; } @@ -485,7 +489,7 @@ public: "(N4901 [optional.monadic]/5)."); if (this->_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), _STD move(this->_Value)); + return _STD invoke(_STD forward<_Fn>(_Func), static_cast<_Ty&&>(this->_Value)); } else { return remove_cvref_t<_Uty>{}; } @@ -500,7 +504,7 @@ public: "(N4901 [optional.monadic]/5)."); if (this->_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), _STD move(this->_Value)); + return _STD invoke(_STD forward<_Fn>(_Func), static_cast(this->_Value)); } else { return remove_cvref_t<_Uty>{}; } @@ -518,7 +522,8 @@ public: "(N4901 [optional.monadic]/8)."); if (this->_Has_value) { - return optional<_Uty>{_Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), this->_Value}; + return optional<_Uty>{ + _Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), static_cast<_Ty&>(this->_Value)}; } else { return optional<_Uty>{}; } @@ -536,7 +541,8 @@ public: "(N4901 [optional.monadic]/8)."); if (this->_Has_value) { - return optional<_Uty>{_Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), this->_Value}; + return optional<_Uty>{ + _Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), static_cast(this->_Value)}; } else { return optional<_Uty>{}; } @@ -555,7 +561,7 @@ public: if (this->_Has_value) { return optional<_Uty>{ - _Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _STD move(this->_Value)}; + _Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), static_cast<_Ty&&>(this->_Value)}; } else { return optional<_Uty>{}; } @@ -574,7 +580,7 @@ public: if (this->_Has_value) { return optional<_Uty>{ - _Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _STD move(this->_Value)}; + _Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), static_cast(this->_Value)}; } else { return optional<_Uty>{}; } diff --git a/stl/inc/ranges b/stl/inc/ranges index ab03fe9702f..2617b7c4c4a 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -290,7 +290,7 @@ namespace ranges { requires copy_constructible<_Ty> : _Engaged{_That._Engaged} { if (_That._Engaged) { - _Construct_in_place(_Val, _That._Val); + _STD _Construct_in_place(_Val, static_cast(_That._Val)); } } @@ -300,7 +300,7 @@ namespace ranges { constexpr _Movable_box(_Movable_box&& _That) : _Engaged{_That._Engaged} { if (_That._Engaged) { - _Construct_in_place(_Val, _STD move(_That._Val)); + _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); } } @@ -315,14 +315,14 @@ namespace ranges { { if (_Engaged) { if (_That._Engaged) { - _Val = _That._Val; + static_cast<_Ty&>(_Val) = static_cast(_That._Val); } else { _Val.~_Ty(); _Engaged = false; } } else { if (_That._Engaged) { - _Construct_in_place(_Val, _That._Val); + _STD _Construct_in_place(_Val, static_cast(_That._Val)); _Engaged = true; } else { // nothing to do @@ -345,7 +345,7 @@ namespace ranges { } if (_That._Engaged) { - _Construct_in_place(_Val, _That._Val); + _STD _Construct_in_place(_Val, static_cast(_That._Val)); _Engaged = true; } @@ -363,14 +363,14 @@ namespace ranges { { if (_Engaged) { if (_That._Engaged) { - _Val = _STD move(_That._Val); + static_cast<_Ty&>(_Val) = static_cast<_Ty&&>(_That._Val); } else { _Val.~_Ty(); _Engaged = false; } } else { if (_That._Engaged) { - _Construct_in_place(_Val, _STD move(_That._Val)); + _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); _Engaged = true; } else { // nothing to do @@ -391,7 +391,7 @@ namespace ranges { } if (_That._Engaged) { - _Construct_in_place(_Val, _STD move(_That._Val)); + _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); _Engaged = true; } @@ -413,7 +413,7 @@ namespace ranges { private: union { - _Ty _Val; + remove_cv_t<_Ty> _Val; }; bool _Engaged; }; @@ -429,6 +429,9 @@ namespace ranges { // is_nothrow_move_constructible_v is true. : movable<_Ty> || is_nothrow_move_constructible_v<_Ty>); + template + concept _Copy_constructible_for_box = is_copy_constructible_v<_Ty>; + template <_Valid_movable_box_object _Ty> requires _Use_simple_movable_box_wrapper<_Ty> class _Movable_box<_Ty> { // provide the same API more efficiently when we can avoid the disengaged state @@ -442,31 +445,50 @@ namespace ranges { is_nothrow_constructible_v<_Ty, _Types...>) // strengthened : _Val(_STD forward<_Types>(_Args)...) {} - _Movable_box(const _Movable_box&) = default; - _Movable_box(_Movable_box&&) = default; + // clang-format off + _Movable_box(const _Movable_box&) + requires _Copy_constructible_for_box<_Ty> && is_trivially_copy_constructible_v<_Ty> = default; + _Movable_box(_Movable_box&&) requires is_trivially_move_constructible_v<_Ty> = default; + // clang-format on + + constexpr _Movable_box(const _Movable_box& _That) noexcept(is_nothrow_copy_constructible_v<_Ty>) + requires _Copy_constructible_for_box<_Ty> + : _Val(static_cast(_That._Val)) {} + + constexpr _Movable_box(_Movable_box&& _That) noexcept(is_nothrow_move_constructible_v<_Ty>) + : _Val(static_cast<_Ty&&>(_That._Val)) {} // clang-format off - _Movable_box& operator=(const _Movable_box&) requires copyable<_Ty> = default; - _Movable_box& operator=(_Movable_box&&) requires movable<_Ty> = default; + _Movable_box& operator=(const _Movable_box&) + requires copyable<_Ty> && is_trivially_copy_assignable_v<_Ty> = default; + _Movable_box& operator=(_Movable_box&&) requires movable<_Ty> && is_trivially_move_assignable_v<_Ty> = default; // clang-format on - constexpr _Movable_box& operator=(const _Movable_box& _That) noexcept + constexpr _Movable_box& operator=(const _Movable_box& _That) noexcept( + is_nothrow_copy_assignable_v<_Ty> || !copyable<_Ty>) // strengthened requires copy_constructible<_Ty> { - if (_STD addressof(_That) != this) { - _Val.~_Ty(); - _Construct_in_place(_Val, _That._Val); + if constexpr (copyable<_Ty>) { + static_cast<_Ty&>(_Val) = static_cast(_That._Val); + } else { + if (_STD addressof(_That) != this) { + _Val.~_Ty(); + _STD _Construct_in_place(_Val, static_cast(_That._Val)); + } } - return *this; } - constexpr _Movable_box& operator=(_Movable_box&& _That) noexcept { - if (_STD addressof(_That) != this) { - _Val.~_Ty(); - _Construct_in_place(_Val, _STD move(_That._Val)); + constexpr _Movable_box& operator=(_Movable_box&& _That) noexcept( + is_nothrow_move_assignable_v<_Ty> || !movable<_Ty>) /* strengthened */ { + if constexpr (movable<_Ty>) { + static_cast<_Ty&>(_Val) = static_cast<_Ty&&>(_That._Val); + } else { + if (_STD addressof(_That) != this) { + _Val.~_Ty(); + _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); + } } - return *this; } @@ -482,7 +504,7 @@ namespace ranges { } private: - /* [[no_unique_address]] */ _Ty _Val{}; + /* [[no_unique_address]] */ remove_cv_t<_Ty> _Val{}; }; template @@ -507,7 +529,7 @@ namespace ranges { requires copy_constructible<_Ty> : _Engaged{_That._Engaged} { if (_That._Engaged) { - _Construct_in_place(_Val, _That._Val); + _STD _Construct_in_place(_Val, static_cast(_That._Val)); } } @@ -517,7 +539,7 @@ namespace ranges { constexpr _Defaultabox(_Defaultabox&& _That) : _Engaged{_That._Engaged} { if (_That._Engaged) { - _Construct_in_place(_Val, _STD move(_That._Val)); + _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); } } @@ -525,7 +547,7 @@ namespace ranges { requires convertible_to constexpr _Defaultabox(const _Defaultabox<_Uty>& _That) : _Engaged{_That} { if (_That) { - _Construct_in_place(_Val, *_That); + _STD _Construct_in_place(_Val, *_That); } } @@ -533,7 +555,7 @@ namespace ranges { requires convertible_to<_Uty, _Ty> constexpr _Defaultabox(_Defaultabox<_Uty>&& _That) : _Engaged{_That} { if (_That) { - _Construct_in_place(_Val, _STD move(*_That)); + _STD _Construct_in_place(_Val, _STD move(*_That)); } } @@ -548,14 +570,14 @@ namespace ranges { { if (_Engaged) { if (_That._Engaged) { - _Val = _That._Val; + static_cast<_Ty&>(_Val) = static_cast(_That._Val); } else { _Val.~_Ty(); _Engaged = false; } } else { if (_That._Engaged) { - _Construct_in_place(_Val, _That._Val); + _STD _Construct_in_place(_Val, static_cast(_That._Val)); _Engaged = true; } else { // nothing to do @@ -573,14 +595,14 @@ namespace ranges { is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>) /* strengthened */ { if (_Engaged) { if (_That._Engaged) { - _Val = _STD move(_That._Val); + static_cast<_Ty&>(_Val) = static_cast<_Ty&&>(_That._Val); } else { _Val.~_Ty(); _Engaged = false; } } else { if (_That._Engaged) { - _Construct_in_place(_Val, _STD move(_That._Val)); + _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); _Engaged = true; } else { // nothing to do @@ -593,9 +615,9 @@ namespace ranges { constexpr _Defaultabox& operator=(_Ty&& _That) noexcept( is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>) { if (_Engaged) { - _Val = _STD move(_That); + static_cast<_Ty&>(_Val) = _STD move(_That); } else { - _Construct_in_place(_Val, _STD move(_That)); + _STD _Construct_in_place(_Val, _STD move(_That)); _Engaged = true; } @@ -607,9 +629,9 @@ namespace ranges { requires copyable<_Ty> { if (_Engaged) { - _Val = _That; + static_cast<_Ty&>(_Val) = _That; } else { - _Construct_in_place(_Val, _That); + _STD _Construct_in_place(_Val, _That); _Engaged = true; } @@ -636,14 +658,16 @@ namespace ranges { } } - _NODISCARD constexpr bool operator==(const _Defaultabox& _That) const noexcept(noexcept(_Val == _That._Val)) { + _NODISCARD constexpr bool operator==(const _Defaultabox& _That) const + noexcept(noexcept(static_cast(_Val) == static_cast(_That._Val))) { _STL_INTERNAL_STATIC_ASSERT(equality_comparable<_Ty>); - return _Engaged == _That._Engaged && (!_Engaged || _Val == _That._Val); + return _Engaged == _That._Engaged + && (!_Engaged || static_cast(_Val) == static_cast(_That._Val)); } private: union { - _Ty _Val; + remove_cv_t<_Ty> _Val; }; bool _Engaged = false; }; @@ -775,7 +799,7 @@ namespace ranges { _Engaged = false; } - _Construct_in_place(_Val, _STD forward<_Types>(_Args)...); + _STD _Construct_in_place(_Val, _STD forward<_Types>(_Args)...); _Engaged = true; return _Val; @@ -783,7 +807,7 @@ namespace ranges { private: union { - _Ty _Val; + remove_cv_t<_Ty> _Val; }; bool _Engaged = false; }; @@ -818,13 +842,13 @@ namespace ranges { template constexpr _Ty& _Emplace(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) { - _Construct_in_place(_Val, _STD forward<_Types>(_Args)...); + _STD _Construct_in_place(_Val, _STD forward<_Types>(_Args)...); return _Val; } private: union { - _Ty _Val; + remove_cv_t<_Ty> _Val; }; }; @@ -1894,7 +1918,7 @@ namespace ranges { enum class _St { _None, _View, _Ref, _Own }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { if constexpr (view>) { if constexpr (convertible_to<_Rng, remove_cvref_t<_Rng>>) { return {_St::_View, is_nothrow_convertible_v<_Rng, remove_cvref_t<_Rng>>}; @@ -2026,7 +2050,7 @@ namespace ranges { enum class _St { _None, _All, _As_rvalue }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { if constexpr (same_as, range_reference_t<_Rng>>) { return {_St::_All, noexcept(views::all(_STD declval<_Rng>()))}; } else if constexpr (_Can_as_rvalue<_Rng>) { @@ -2967,7 +2991,7 @@ namespace ranges { }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { using _Ty = remove_cvref_t<_Rng>; if constexpr (_Is_specialization_v<_Ty, empty_view>) { @@ -3366,7 +3390,7 @@ namespace ranges { }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { using _Ty = remove_cvref_t<_Rng>; if constexpr (_Is_specialization_v<_Ty, empty_view>) { @@ -4136,18 +4160,18 @@ namespace ranges { template constexpr _Ret _Visit_inner_it(auto&& _Func) const { if (_Inner_it._Contains == _Variantish_state::_Holds_first) { - return _Func(_Inner_it._First); + return _Func(_Inner_it._Get_first()); } else if (_Inner_it._Contains == _Variantish_state::_Holds_second) { - return _Func(_Inner_it._Second); + return _Func(_Inner_it._Get_second()); } else { - _Throw_bad_variant_access(); + _STD _Throw_bad_variant_access(); } } constexpr void _Satisfy() { for (;;) { if (_Inner_it._Contains == _Variantish_state::_Holds_first) { - if (_Inner_it._First != _RANGES end(_Parent->_Pattern)) { + if (_Inner_it._Get_first() != _RANGES end(_Parent->_Pattern)) { break; } @@ -4155,7 +4179,7 @@ namespace ranges { } else { _STL_INTERNAL_CHECK(_Inner_it._Contains == _Variantish_state::_Holds_second); - if (_Inner_it._Second != _RANGES end(_Get_inner())) { + if (_Inner_it._Get_second() != _RANGES end(_Get_inner())) { break; } @@ -4195,13 +4219,13 @@ namespace ranges { : _Mybase(_STD move(_It._Outer_it)), _Parent(_It._Parent) { switch (_It._Inner_it._Contains) { case _Variantish_state::_Holds_first: - _Inner_it._Emplace_first(_STD move(_It._Inner_it._First)); + _Inner_it._Emplace_first(_STD move(_It._Inner_it._Get_first())); break; case _Variantish_state::_Holds_second: - _Inner_it._Emplace_second(_STD move(_It._Inner_it._Second)); + _Inner_it._Emplace_second(_STD move(_It._Inner_it._Get_second())); break; case _Variantish_state::_Nothing: - _Throw_bad_variant_access(); + _STD _Throw_bad_variant_access(); } } @@ -4213,13 +4237,13 @@ namespace ranges { constexpr _Iterator& operator++() { switch (_Inner_it._Contains) { case _Variantish_state::_Holds_first: - ++_Inner_it._First; + ++_Inner_it._Get_first(); break; case _Variantish_state::_Holds_second: - ++_Inner_it._Second; + ++_Inner_it._Get_second(); break; case _Variantish_state::_Nothing: - _Throw_bad_variant_access(); + _STD _Throw_bad_variant_access(); } _Satisfy(); return *this; @@ -4249,7 +4273,7 @@ namespace ranges { for (;;) { if (_Inner_it._Contains == _Variantish_state::_Holds_first) { - auto& _It = _Inner_it._First; + auto& _It = _Inner_it._Get_first(); if (_It == _RANGES begin(_Parent->_Pattern)) { --_Outer_it; _Inner_it._Emplace_second(_RANGES end(_Get_inner())); @@ -4257,26 +4281,26 @@ namespace ranges { break; } } else if (_Inner_it._Contains == _Variantish_state::_Holds_second) { - auto& _It = _Inner_it._Second; + auto& _It = _Inner_it._Get_second(); if (_It == _RANGES begin(_Get_inner())) { _Inner_it._Emplace_first(_RANGES end(_Parent->_Pattern)); } else { break; } } else { - _Throw_bad_variant_access(); + _STD _Throw_bad_variant_access(); } } switch (_Inner_it._Contains) { case _Variantish_state::_Holds_first: - --_Inner_it._First; + --_Inner_it._Get_first(); break; case _Variantish_state::_Holds_second: - --_Inner_it._Second; + --_Inner_it._Get_second(); break; case _Variantish_state::_Nothing: - _Throw_bad_variant_access(); + _STD _Throw_bad_variant_access(); } return *this; } @@ -4303,9 +4327,9 @@ namespace ranges { switch (_Left._Inner_it._Contains) { case _Variantish_state::_Holds_first: - return _Left._Inner_it._First == _Right._Inner_it._First; + return _Left._Inner_it._Get_first() == _Right._Inner_it._Get_first(); case _Variantish_state::_Holds_second: - return _Left._Inner_it._Second == _Right._Inner_it._Second; + return _Left._Inner_it._Get_second() == _Right._Inner_it._Get_second(); case _Variantish_state::_Nothing: return true; } @@ -4326,9 +4350,9 @@ namespace ranges { case _Variantish_state::_Holds_first: switch (_Right._Inner_it._Contains) { case _Variantish_state::_Holds_first: - return _RANGES iter_swap(_Left._Inner_it._First, _Right._Inner_it._First); + return _RANGES iter_swap(_Left._Inner_it._Get_first(), _Right._Inner_it._Get_first()); case _Variantish_state::_Holds_second: - return _RANGES iter_swap(_Left._Inner_it._First, _Right._Inner_it._Second); + return _RANGES iter_swap(_Left._Inner_it._Get_first(), _Right._Inner_it._Get_second()); case _Variantish_state::_Nothing: break; } @@ -4336,9 +4360,9 @@ namespace ranges { case _Variantish_state::_Holds_second: switch (_Right._Inner_it._Contains) { case _Variantish_state::_Holds_first: - return _RANGES iter_swap(_Left._Inner_it._Second, _Right._Inner_it._First); + return _RANGES iter_swap(_Left._Inner_it._Get_second(), _Right._Inner_it._Get_first()); case _Variantish_state::_Holds_second: - return _RANGES iter_swap(_Left._Inner_it._Second, _Right._Inner_it._Second); + return _RANGES iter_swap(_Left._Inner_it._Get_second(), _Right._Inner_it._Get_second()); case _Variantish_state::_Nothing: break; } @@ -4347,7 +4371,7 @@ namespace ranges { break; } - _Throw_bad_variant_access(); + _STD _Throw_bad_variant_access(); } }; @@ -5115,7 +5139,7 @@ namespace ranges { enum class _St { _None, _Span, _Subrange, _Subrange_counted }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { using _Decayed = decay_t<_It>; _STL_INTERNAL_STATIC_ASSERT(input_or_output_iterator<_Decayed>); if constexpr (contiguous_iterator<_Decayed>) { @@ -5244,7 +5268,7 @@ namespace ranges { enum class _St { _None, _All, _Common }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { if constexpr (common_range<_Rng>) { return {_St::_All, noexcept(views::all(_STD declval<_Rng>()))}; } else if constexpr (copyable>) { @@ -5376,7 +5400,7 @@ namespace ranges { static_cast(_Ki); template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { using _Ty = remove_cvref_t<_Rng>; if constexpr (_Is_specialization_v<_Ty, reverse_view>) { @@ -5510,7 +5534,7 @@ namespace ranges { static constexpr bool _Can_reconstruct_ref_view_v> = true; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { using _Ty = remove_cvref_t<_Rng>; if constexpr (constant_range>) { @@ -8304,7 +8328,7 @@ namespace ranges { }; template - _NODISCARD static _CONSTEVAL bool _Is_end_noexcept() noexcept { + _NODISCARD static consteval bool _Is_end_noexcept() noexcept { if constexpr (!_Zip_is_common<_Maybe_const<_IsConst, _ViewTypes>...>) { return noexcept(_Sentinel<_IsConst>{ _Tuple_transform(_RANGES end, _STD declval<_Maybe_const<_IsConst, tuple<_ViewTypes...>>&>())}); @@ -8396,7 +8420,7 @@ namespace ranges { struct _Zip_fn { private: template - _NODISCARD static _CONSTEVAL bool _Is_invocation_noexcept() { + _NODISCARD static consteval bool _Is_invocation_noexcept() { if constexpr (sizeof...(_Types) == 0) { // NOTE: views::empty> is nothrow copy-constructible. return true; @@ -8666,7 +8690,7 @@ namespace ranges { }; template - _NODISCARD static _CONSTEVAL bool _Is_end_noexcept() noexcept { + _NODISCARD static consteval bool _Is_end_noexcept() noexcept { if constexpr (common_range<_Maybe_const<_IsConst, _Inner_view>>) { return noexcept(_Iterator<_IsConst>{_STD declval<_Maybe_const<_IsConst, zip_transform_view>&>(), _STD declval<_Maybe_const<_IsConst, _Inner_view>&>().end()}); diff --git a/stl/inc/shared_mutex b/stl/inc/shared_mutex index a194f17b6fc..824596e26a2 100644 --- a/stl/inc/shared_mutex +++ b/stl/inc/shared_mutex @@ -189,11 +189,6 @@ public: return _Try_lock_shared_until(_Abs_time); } - _NODISCARD_TRY_CHANGE_STATE bool try_lock_shared_until( - const xtime* _Abs_time) { // try to lock non-exclusive until absolute time - return _Try_lock_shared_until(_Abs_time); - } - void unlock_shared() { // unlock non-exclusive _Read_cnt_t _Local_readers; bool _Local_writing; diff --git a/stl/inc/source_location b/stl/inc/source_location index 5bd56d4eae9..2090b69aefb 100644 --- a/stl/inc/source_location +++ b/stl/inc/source_location @@ -8,9 +8,9 @@ #define _SOURCE_LOCATION_ #include #if _STL_COMPILER_PREPROCESSOR -#ifndef __cpp_consteval -_EMIT_STL_WARNING(STL4038, "The contents of are available only with C++20 consteval support."); -#else // ^^^ !defined(__cpp_consteval) / defined(__cpp_consteval) vvv +#if !_HAS_CXX20 +_EMIT_STL_WARNING(STL4038, "The contents of are available only with C++20 or later."); +#else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv #include @@ -66,6 +66,6 @@ _STD_END _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) -#endif // !defined(__cpp_consteval) +#endif // _HAS_CXX20 #endif // _STL_COMPILER_PREPROCESSOR #endif // _SOURCE_LOCATION_ diff --git a/stl/inc/thread b/stl/inc/thread index 18f862c5ff3..6d8f83c0260 100644 --- a/stl/inc/thread +++ b/stl/inc/thread @@ -181,10 +181,6 @@ namespace this_thread { _Thrd_yield(); } - inline void sleep_until(const xtime* _Abs_time) { - _Thrd_sleep(_Abs_time); - } - _EXPORT_STD template void sleep_until(const chrono::time_point<_Clock, _Duration>& _Abs_time) { #if _HAS_CXX20 @@ -196,8 +192,8 @@ namespace this_thread { return; } - _CSTD xtime _Tgt; - (void) _To_xtime_10_day_clamped(_Tgt, _Abs_time - _Now); + _timespec64 _Tgt; + (void) _To_timespec64_sys_10_day_clamped(_Tgt, _Abs_time - _Now); _Thrd_sleep(&_Tgt); } } diff --git a/stl/inc/utility b/stl/inc/utility index b3e4858212c..7bd0866585c 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -848,7 +848,7 @@ _NODISCARD constexpr bool cmp_greater_equal(const _Ty1 _Left, const _Ty2 _Right) } template -_NODISCARD _CONSTEVAL _Ty _Min_limit() noexcept { // same as (numeric_limits<_Ty>::min)(), less throughput cost +_NODISCARD consteval _Ty _Min_limit() noexcept { // same as (numeric_limits<_Ty>::min)(), less throughput cost static_assert(_Is_standard_integer<_Ty>); // doesn't attempt to handle all types if constexpr (is_signed_v<_Ty>) { constexpr auto _Unsigned_max = static_cast>(-1); @@ -859,7 +859,7 @@ _NODISCARD _CONSTEVAL _Ty _Min_limit() noexcept { // same as (numeric_limits<_Ty } template -_NODISCARD _CONSTEVAL _Ty _Max_limit() noexcept { // same as (numeric_limits<_Ty>::max)(), less throughput cost +_NODISCARD consteval _Ty _Max_limit() noexcept { // same as (numeric_limits<_Ty>::max)(), less throughput cost static_assert(_Is_standard_integer<_Ty>); // doesn't attempt to handle all types if constexpr (is_signed_v<_Ty>) { constexpr auto _Unsigned_max = static_cast>(-1); diff --git a/stl/inc/variant b/stl/inc/variant index c0008799ea1..670c5b4af3e 100644 --- a/stl/inc/variant +++ b/stl/inc/variant @@ -377,7 +377,7 @@ class _Variant_storage_ { // Storage for variant alterna public: static constexpr size_t _Size = 1 + sizeof...(_Rest); union { - remove_const_t<_First> _Head; + remove_cv_t<_First> _Head; _Variant_storage<_Rest...> _Tail; }; @@ -412,7 +412,7 @@ class _Variant_storage_ { // Storage for variant altern public: static constexpr size_t _Size = 1 + sizeof...(_Rest); union { - remove_const_t<_First> _Head; + remove_cv_t<_First> _Head; _Variant_storage<_Rest...> _Tail; }; @@ -457,7 +457,7 @@ public: // wrapper to enable minimal hats-in-variants support. template struct _Variant_item { - remove_const_t<_Ty> _Item; + remove_cv_t<_Ty> _Item; template constexpr _Variant_item(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index e1dd28ef45c..6f2a28fb780 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -704,13 +704,10 @@ struct _Default_allocator_traits { // traits for std::allocator template static _CONSTEXPR20 void construct(_Alloc&, _Objty* const _Ptr, _Types&&... _Args) { #if _HAS_CXX20 - if (_STD is_constant_evaluated()) { - _STD construct_at(_Ptr, _STD forward<_Types>(_Args)...); - } else -#endif // _HAS_CXX20 - { - ::new (_Voidify_iter(_Ptr)) _Objty(_STD forward<_Types>(_Args)...); - } + _STD construct_at(_Ptr, _STD forward<_Types>(_Args)...); +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv + ::new (const_cast(static_cast(_Ptr))) _Objty(_STD forward<_Types>(_Args)...); +#endif // ^^^ !_HAS_CXX20 ^^^ } template @@ -978,7 +975,7 @@ public: template _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS void construct(_Objty* const _Ptr, _Types&&... _Args) { - ::new (_Voidify_iter(_Ptr)) _Objty(_STD forward<_Types>(_Args)...); + ::new (const_cast(static_cast(_Ptr))) _Objty(_STD forward<_Types>(_Args)...); } template @@ -1634,9 +1631,11 @@ _CONSTEXPR20 _NoThrowFwdIt _Uninitialized_move_unchecked(_InIt _First, const _In #ifdef __cpp_lib_concepts namespace ranges { template - concept _No_throw_input_iterator = input_iterator<_It> // - && is_lvalue_reference_v> // - && same_as>, iter_value_t<_It>>; + concept _No_throw_input_iterator = + input_iterator<_It> // + && is_lvalue_reference_v> // + && same_as>, remove_reference_t>> // per LWG-3888 + && same_as>, iter_value_t<_It>>; template concept _No_throw_sentinel_for = sentinel_for<_Se, _It>; diff --git a/stl/inc/xpolymorphic_allocator.h b/stl/inc/xpolymorphic_allocator.h index 5957f4333d0..44ae61c4bd6 100644 --- a/stl/inc/xpolymorphic_allocator.h +++ b/stl/inc/xpolymorphic_allocator.h @@ -279,7 +279,13 @@ namespace pmr { void construct(_Uty* const _Ptr, _Types&&... _Args) { // propagate allocator *this if uses_allocator_v, polymorphic_allocator> #if _HAS_CXX20 - _STD uninitialized_construct_using_allocator(_Ptr, *this, _STD forward<_Types>(_Args)...); + // equivalent to calling uninitialized_construct_using_allocator except for handling of cv-qualification + _STD apply( + [_Ptr](auto&&... _Construct_args) { + return ::new (const_cast(static_cast(_Ptr))) + _Uty(_STD forward(_Construct_args)...); + }, + _STD uses_allocator_construction_args<_Uty>(*this, _STD forward<_Types>(_Args)...)); #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv allocator _Al{}; if constexpr (_Is_cv_pair<_Uty>) { diff --git a/stl/inc/xsmf_control.h b/stl/inc/xsmf_control.h index a288c7e3047..54ad04b67c7 100644 --- a/stl/inc/xsmf_control.h +++ b/stl/inc/xsmf_control.h @@ -34,10 +34,20 @@ struct _Non_trivial_copy : _Base { // non-trivial copy construction facade _Non_trivial_copy& operator=(_Non_trivial_copy&&) = default; }; +template +struct _Deleted_copy : _Base { // deleted copy construction facade + using _Base::_Base; + + _Deleted_copy() = default; + _Deleted_copy(const _Deleted_copy&) = delete; + _Deleted_copy(_Deleted_copy&&) = default; + _Deleted_copy& operator=(const _Deleted_copy&) = default; + _Deleted_copy& operator=(_Deleted_copy&&) = default; +}; + template -using _SMF_control_copy = conditional_t< - conjunction_v..., negation...>>>, - _Non_trivial_copy<_Base>, _Base>; +using _SMF_control_copy = conditional_t...>, _Base, + conditional_t...>, _Non_trivial_copy<_Base>, _Deleted_copy<_Base>>>; template struct _Non_trivial_move : _SMF_control_copy<_Base, _Types...> { // non-trivial move construction facade @@ -55,9 +65,22 @@ struct _Non_trivial_move : _SMF_control_copy<_Base, _Types...> { // non-trivial }; template -using _SMF_control_move = conditional_t< - conjunction_v..., negation...>>>, - _Non_trivial_move<_Base, _Types...>, _SMF_control_copy<_Base, _Types...>>; +struct _Deleted_move : _SMF_control_copy<_Base, _Types...> { // deleted move construction facade + using _Mybase = _SMF_control_copy<_Base, _Types...>; + using _Mybase::_Mybase; + + _Deleted_move() = default; + _Deleted_move(const _Deleted_move&) = default; + _Deleted_move(_Deleted_move&&) = delete; + _Deleted_move& operator=(const _Deleted_move&) = default; + _Deleted_move& operator=(_Deleted_move&&) = default; +}; + +template +using _SMF_control_move = + conditional_t...>, _SMF_control_copy<_Base, _Types...>, + conditional_t...>, _Non_trivial_move<_Base, _Types...>, + _Deleted_move<_Base, _Types...>>>; template struct _Non_trivial_copy_assign : _SMF_control_move<_Base, _Types...> { // non-trivial copy assignment facade diff --git a/stl/inc/xthreads.h b/stl/inc/xthreads.h index 83c04c3fb50..71503026c25 100644 --- a/stl/inc/xthreads.h +++ b/stl/inc/xthreads.h @@ -67,7 +67,7 @@ enum { _Thrd_success, _Thrd_nomem, _Thrd_timedout, _Thrd_busy, _Thrd_error }; // threads _CRTIMP2_PURE int __cdecl _Thrd_detach(_Thrd_t); _CRTIMP2_PURE int __cdecl _Thrd_join(_Thrd_t, int*); -_CRTIMP2_PURE void __cdecl _Thrd_sleep(const xtime*); +_CRTIMP2_PURE void __cdecl _Thrd_sleep(const _timespec64*); _CRTIMP2_PURE void __cdecl _Thrd_yield(); _CRTIMP2_PURE unsigned int __cdecl _Thrd_hardware_concurrency(); _CRTIMP2_PURE _Thrd_id_t __cdecl _Thrd_id(); @@ -87,7 +87,7 @@ _CRTIMP2_PURE void __cdecl _Mtx_destroy_in_situ(_Mtx_t); _CRTIMP2_PURE int __cdecl _Mtx_current_owns(_Mtx_t); _CRTIMP2_PURE int __cdecl _Mtx_lock(_Mtx_t); _CRTIMP2_PURE int __cdecl _Mtx_trylock(_Mtx_t); -_CRTIMP2_PURE int __cdecl _Mtx_timedlock(_Mtx_t, const xtime*); +_CRTIMP2_PURE int __cdecl _Mtx_timedlock(_Mtx_t, const _timespec64*); _CRTIMP2_PURE int __cdecl _Mtx_unlock(_Mtx_t); // TRANSITION, ABI: always returns _Thrd_success _CRTIMP2_PURE void* __cdecl _Mtx_getconcrtcs(_Mtx_t); @@ -110,7 +110,7 @@ _CRTIMP2_PURE void __cdecl _Cnd_destroy(_Cnd_t); _CRTIMP2_PURE void __cdecl _Cnd_init_in_situ(_Cnd_t); _CRTIMP2_PURE void __cdecl _Cnd_destroy_in_situ(_Cnd_t); _CRTIMP2_PURE int __cdecl _Cnd_wait(_Cnd_t, _Mtx_t); // TRANSITION, ABI: Always returns _Thrd_success -_CRTIMP2_PURE int __cdecl _Cnd_timedwait(_Cnd_t, _Mtx_t, const xtime*); +_CRTIMP2_PURE int __cdecl _Cnd_timedwait(_Cnd_t, _Mtx_t, const _timespec64*); _CRTIMP2_PURE int __cdecl _Cnd_broadcast(_Cnd_t); // TRANSITION, ABI: Always returns _Thrd_success _CRTIMP2_PURE int __cdecl _Cnd_signal(_Cnd_t); // TRANSITION, ABI: Always returns _Thrd_success _CRTIMP2_PURE void __cdecl _Cnd_register_at_thread_exit(_Cnd_t, _Mtx_t, int*); diff --git a/stl/inc/xtimec.h b/stl/inc/xtimec.h index 49785d48768..2e1aa0aa4bc 100644 --- a/stl/inc/xtimec.h +++ b/stl/inc/xtimec.h @@ -20,17 +20,12 @@ _STL_DISABLE_CLANG_WARNINGS _EXTERN_C -struct xtime { // store time with nanosecond resolution - __time64_t sec; - long nsec; -}; - -_CRTIMP2_PURE long __cdecl _Xtime_diff_to_millis2(const xtime*, const xtime*); +_CRTIMP2_PURE long __cdecl _Xtime_diff_to_millis2(const _timespec64*, const _timespec64*); _CRTIMP2_PURE long long __cdecl _Xtime_get_ticks(); #ifdef _CRTBLD // Used by several src files, but not dllexported. -void _Xtime_get2(xtime*); +void _Timespec64_get_sys(_timespec64*); #endif // _CRTBLD _CRTIMP2_PURE long long __cdecl _Query_perf_counter(); diff --git a/stl/inc/xutility b/stl/inc/xutility index 8b9046287cc..398013dc7ea 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -230,26 +230,19 @@ struct _Get_rebind_alias<_Ty, _Other, void_t; }; -template -_NODISCARD constexpr void* _Voidify_iter(_Iter _It) noexcept { - if constexpr (is_pointer_v<_Iter>) { - return const_cast(static_cast(_It)); - } else { - return const_cast(static_cast(_STD addressof(*_It))); - } -} - #if _HAS_CXX20 #ifdef __EDG__ // TRANSITION, DevCom-1691516 +// per LWG-3888 _EXPORT_STD template ()) _Ty(_STD declval<_Types>()...))>> + class = void_t(_STD declval<_Ty*>())) _Ty(_STD declval<_Types>()...))>> #else // ^^^ no workaround / workaround vvv +// per LWG-3888 _EXPORT_STD template ()) _Ty(_STD declval<_Types>()...))>* = nullptr> + void_t(_STD declval<_Ty*>())) _Ty(_STD declval<_Types>()...))>* = nullptr> #endif // TRANSITION, DevCom-1691516 constexpr _Ty* construct_at(_Ty* const _Location, _Types&&... _Args) noexcept( - noexcept(::new(_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...))) /* strengthened */ { - _MSVC_CONSTEXPR return ::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...); + noexcept(::new(static_cast(_Location)) _Ty(_STD forward<_Types>(_Args)...))) /* strengthened */ { + _MSVC_CONSTEXPR return ::new (static_cast(_Location)) _Ty(_STD forward<_Types>(_Args)...); } #endif // _HAS_CXX20 @@ -262,13 +255,13 @@ _CONSTEXPR20 void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept( } else #endif // _HAS_CXX20 { - ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); + ::new (static_cast(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); } } template void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { - ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty; + ::new (static_cast(_STD addressof(_Obj))) _Ty; } template @@ -445,7 +438,7 @@ namespace ranges { enum class _St { _None, _Custom, _Fallback }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { if constexpr (_Has_ADL<_Ty>) { return {_St::_Custom, noexcept(iter_move(_STD declval<_Ty>()))}; // intentional ADL } else if constexpr (_Can_deref<_Ty>) { @@ -770,7 +763,7 @@ namespace ranges { enum class _St { _None, _Custom, _Swap, _Exchange }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { if constexpr (_Has_ADL<_Ty1, _Ty2>) { return {_St::_Custom, noexcept(iter_swap(_STD declval<_Ty1>(), _STD declval<_Ty2>()))}; // intentional ADL @@ -1833,7 +1826,7 @@ private: using _Reference = iter_const_reference_t<_Iter>; using _Rvalue_reference = _Iter_const_rvalue_reference_t<_Iter>; - _NODISCARD static _CONSTEVAL auto _Get_iter_concept() noexcept { + _NODISCARD static consteval auto _Get_iter_concept() noexcept { if constexpr (contiguous_iterator<_Iter>) { return contiguous_iterator_tag{}; } else if constexpr (random_access_iterator<_Iter>) { @@ -2155,7 +2148,7 @@ namespace ranges { enum class _St { _None, _Array, _Member, _Non_member }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { _STL_INTERNAL_STATIC_ASSERT(is_lvalue_reference_v<_Ty>); if constexpr (is_array_v>) { static_assert(_Has_complete_elements<_Ty>, @@ -2224,7 +2217,7 @@ namespace ranges { enum class _St { _None, _Array, _Member, _Non_member }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { _STL_INTERNAL_STATIC_ASSERT(is_lvalue_reference_v<_Ty>); using _UnRef = remove_reference_t<_Ty>; @@ -2371,7 +2364,7 @@ namespace ranges { enum class _St { _None, _Member, _Unwrap }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { _STL_INTERNAL_STATIC_ASSERT(is_lvalue_reference_v<_Ty>); if constexpr (_Has_member<_Ty>) { _STL_INTERNAL_STATIC_ASSERT( @@ -2425,7 +2418,7 @@ namespace ranges { enum class _St { _None, _Member, _Unwrap }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { _STL_INTERNAL_STATIC_ASSERT(is_lvalue_reference_v<_Ty>); if constexpr (_Has_member<_Ty>) { return {_St::_Member, noexcept(_STD declval<_Ty>()._Unchecked_end())}; @@ -2590,7 +2583,7 @@ namespace ranges { enum class _St { _None, _Member, _Non_member, _Make_reverse }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { _STL_INTERNAL_STATIC_ASSERT(is_lvalue_reference_v<_Ty>); if constexpr (_Has_member<_Ty>) { return {_St::_Member, noexcept(_Fake_copy_init(_STD declval<_Ty>().rbegin()))}; @@ -2660,7 +2653,7 @@ namespace ranges { enum class _St { _None, _Member, _Non_member, _Make_reverse }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { _STL_INTERNAL_STATIC_ASSERT(is_lvalue_reference_v<_Ty>); if constexpr (_Has_member<_Ty>) { return {_St::_Member, noexcept(_Fake_copy_init(_STD declval<_Ty>().rend()))}; @@ -2799,7 +2792,7 @@ namespace ranges { enum class _St { _None, _Array, _Member, _Non_member, _Subtract }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { _STL_INTERNAL_STATIC_ASSERT(is_lvalue_reference_v<_Ty>); using _UnCV = remove_cvref_t<_Ty>; @@ -2869,7 +2862,7 @@ namespace ranges { enum class _St { _None, _Member, _Size, _Compare }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { _STL_INTERNAL_STATIC_ASSERT(is_lvalue_reference_v<_Ty>); if constexpr (is_unbounded_array_v>) { return {_St::_None}; @@ -2933,7 +2926,7 @@ namespace ranges { enum class _St { _None, _Member, _Address }; template - _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { _STL_INTERNAL_STATIC_ASSERT(is_lvalue_reference_v<_Ty>); if constexpr (_Has_member<_Ty>) { return {_St::_Member, noexcept(_STD declval<_Ty>().data())}; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index b80a951e5ad..8f652b7a979 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1675,15 +1675,11 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_remove_cvref 201711L #define __cpp_lib_semaphore 201907L #define __cpp_lib_smart_ptr_for_overwrite 202002L - -#ifdef __cpp_consteval -#define __cpp_lib_source_location 201907L -#endif // __cpp_consteval - -#define __cpp_lib_span 202002L -#define __cpp_lib_ssize 201902L -#define __cpp_lib_starts_ends_with 201711L -#define __cpp_lib_syncbuf 201803L +#define __cpp_lib_source_location 201907L +#define __cpp_lib_span 202002L +#define __cpp_lib_ssize 201902L +#define __cpp_lib_starts_ends_with 201711L +#define __cpp_lib_syncbuf 201803L #ifdef __cpp_lib_concepts #define __cpp_lib_three_way_comparison 201907L @@ -1698,11 +1694,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect // C++23 #if _HAS_CXX23 #define __cpp_lib_adaptor_iterator_pair_constructor 202106L - -#ifdef __cpp_lib_concepts -#define __cpp_lib_allocate_at_least 202106L -#endif // __cpp_lib_concepts - +#define __cpp_lib_allocate_at_least 202302L #define __cpp_lib_associative_heterogeneous_erasure 202110L #define __cpp_lib_bind_back 202202L #define __cpp_lib_byteswap 202110L diff --git a/stl/src/cond.cpp b/stl/src/cond.cpp index bc3acb9dc7f..7545c6805c4 100644 --- a/stl/src/cond.cpp +++ b/stl/src/cond.cpp @@ -60,7 +60,8 @@ int _Cnd_wait(const _Cnd_t cond, const _Mtx_t mtx) { // wait until signaled return _Thrd_success; // TRANSITION, ABI: Always returns _Thrd_success } -int _Cnd_timedwait(const _Cnd_t cond, const _Mtx_t mtx, const xtime* const target) { // wait until signaled or timeout +// wait until signaled or timeout +int _Cnd_timedwait(const _Cnd_t cond, const _Mtx_t mtx, const _timespec64* const target) { int res = _Thrd_success; const auto cs = static_cast(_Mtx_getconcrtcs(mtx)); if (target == nullptr) { // no target time specified, wait on mutex @@ -68,11 +69,11 @@ int _Cnd_timedwait(const _Cnd_t cond, const _Mtx_t mtx, const xtime* const targe cond->_get_cv()->wait(cs); _Mtx_reset_owner(mtx); } else { // target time specified, wait for it - xtime now; - _Xtime_get2(&now); + _timespec64 now; + _Timespec64_get_sys(&now); _Mtx_clear_owner(mtx); if (!cond->_get_cv()->wait_for(cs, _Xtime_diff_to_millis2(target, &now))) { // report timeout - _Xtime_get2(&now); + _Timespec64_get_sys(&now); if (_Xtime_diff_to_millis2(target, &now) == 0) { res = _Thrd_timedout; } diff --git a/stl/src/cthread.cpp b/stl/src/cthread.cpp index 24ff401d428..f10d1ff6c8b 100644 --- a/stl/src/cthread.cpp +++ b/stl/src/cthread.cpp @@ -72,13 +72,13 @@ int _Thrd_detach(_Thrd_t thr) { // tell OS to release thread's resources when it return CloseHandle(thr._Hnd) ? _Thrd_success : _Thrd_error; } -void _Thrd_sleep(const xtime* xt) { // suspend thread until time xt - xtime now; - _Xtime_get2(&now); +void _Thrd_sleep(const _timespec64* xt) { // suspend thread until time xt + _timespec64 now; + _Timespec64_get_sys(&now); do { // sleep and check time Sleep(_Xtime_diff_to_millis2(xt, &now)); - _Xtime_get2(&now); - } while (now.sec < xt->sec || now.sec == xt->sec && now.nsec < xt->nsec); + _Timespec64_get_sys(&now); + } while (now.tv_sec < xt->tv_sec || now.tv_sec == xt->tv_sec && now.tv_nsec < xt->tv_nsec); } void _Thrd_yield() { // surrender remainder of timeslice diff --git a/stl/src/mutex.cpp b/stl/src/mutex.cpp index 543838b1d8a..a58090ebefd 100644 --- a/stl/src/mutex.cpp +++ b/stl/src/mutex.cpp @@ -84,7 +84,7 @@ void _Mtx_destroy(_Mtx_t mtx) { // destroy mutex } } -static int mtx_do_lock(_Mtx_t mtx, const xtime* target) { // lock mutex +static int mtx_do_lock(_Mtx_t mtx, const _timespec64* target) { // lock mutex if ((mtx->type & ~_Mtx_recursive) == _Mtx_plain) { // set the lock if (mtx->thread_id != static_cast(GetCurrentThreadId())) { // not current thread, do lock mtx->_get_cs()->lock(); @@ -102,7 +102,7 @@ static int mtx_do_lock(_Mtx_t mtx, const xtime* target) { // lock mutex res = WAIT_OBJECT_0; - } else if (target->sec < 0 || target->sec == 0 && target->nsec <= 0) { + } else if (target->tv_sec < 0 || target->tv_sec == 0 && target->tv_nsec <= 0) { // target time <= 0 --> plain trylock or timed wait for time that has passed; try to lock with 0 timeout if (mtx->thread_id != static_cast(GetCurrentThreadId())) { // not this thread, lock it if (mtx->_get_cs()->try_lock()) { @@ -115,9 +115,10 @@ static int mtx_do_lock(_Mtx_t mtx, const xtime* target) { // lock mutex } } else { // check timeout - xtime now; - _Xtime_get2(&now); - while (now.sec < target->sec || now.sec == target->sec && now.nsec < target->nsec) { // time has not expired + _timespec64 now; + _Timespec64_get_sys(&now); + while (now.tv_sec < target->tv_sec || now.tv_sec == target->tv_sec && now.tv_nsec < target->tv_nsec) { + // time has not expired if (mtx->thread_id == static_cast(GetCurrentThreadId()) || mtx->_get_cs()->try_lock_for(_Xtime_diff_to_millis2(target, &now))) { // stop waiting res = WAIT_OBJECT_0; @@ -126,7 +127,7 @@ static int mtx_do_lock(_Mtx_t mtx, const xtime* target) { // lock mutex res = WAIT_TIMEOUT; } - _Xtime_get2(&now); + _Timespec64_get_sys(&now); } } @@ -147,7 +148,7 @@ static int mtx_do_lock(_Mtx_t mtx, const xtime* target) { // lock mutex return _Thrd_success; case WAIT_TIMEOUT: - if (target == nullptr || (target->sec == 0 && target->nsec == 0)) { + if (target == nullptr || (target->tv_sec == 0 && target->tv_nsec == 0)) { return _Thrd_busy; } else { return _Thrd_timedout; @@ -175,14 +176,14 @@ int _Mtx_lock(_Mtx_t mtx) { // lock mutex } int _Mtx_trylock(_Mtx_t mtx) { // attempt to lock try_mutex - xtime xt; + _timespec64 xt; _THREAD_ASSERT((mtx->type & (_Mtx_try | _Mtx_timed)) != 0, "trylock not supported by mutex"); - xt.sec = 0; - xt.nsec = 0; + xt.tv_sec = 0; + xt.tv_nsec = 0; return mtx_do_lock(mtx, &xt); } -int _Mtx_timedlock(_Mtx_t mtx, const xtime* xt) { // attempt to lock timed mutex +int _Mtx_timedlock(_Mtx_t mtx, const _timespec64* xt) { // attempt to lock timed mutex int res; _THREAD_ASSERT((mtx->type & _Mtx_timed) != 0, "timedlock not supported by mutex"); diff --git a/stl/src/tzdb.cpp b/stl/src/tzdb.cpp index c43853bdc14..9f92763c856 100644 --- a/stl/src/tzdb.cpp +++ b/stl/src/tzdb.cpp @@ -502,6 +502,12 @@ void __stdcall __std_tzdb_delete_current_zone(__std_tzdb_current_zone_info* cons return _Report_error(_Info, __std_tzdb_error::_Win_error); } + // Get the option stored after the time zone name. If there's no option, _Tz[_Tz_len] is the null terminator in the + // std::string, and will be treated the same as __std_tzdb_sys_info_type::_Full. + const auto _Type = static_cast<__std_tzdb_sys_info_type>(_Tz[_Tz_len]); + + // TRANSITION, vNext + // Profiling shows that _Get_cal is a hot path. Its result should be cached (preferably in the time_zone object). const auto _Cal = _Get_cal(_Tz, _Tz_len, _Info->_Err); if (_Cal == nullptr) { return _Propagate_error(_Info); @@ -528,6 +534,10 @@ void __stdcall __std_tzdb_delete_current_zone(__std_tzdb_current_zone_info* cons return _Report_error(_Info, __std_tzdb_error::_Icu_error); } + if (_Type == __std_tzdb_sys_info_type::_Offset_only) { + return _Info.release(); + } + UDate _Transition{}; _Info->_Begin = __icu_ucal_getTimeZoneTransitionDate(_Cal.get(), UTimeZoneTransitionType::UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE, &_Transition, &_UErr) @@ -545,6 +555,10 @@ void __stdcall __std_tzdb_delete_current_zone(__std_tzdb_current_zone_info* cons return _Report_error(_Info, __std_tzdb_error::_Icu_error); } + if (_Type == __std_tzdb_sys_info_type::_Offset_and_range) { + return _Info.release(); + } + int32_t _Abbrev_len{}; const auto _Abbrev = _Get_timezone_short_id(_Cal.get(), _Is_daylight, _Abbrev_len, _Info->_Err); if (_Abbrev == nullptr) { diff --git a/stl/src/xtime.cpp b/stl/src/xtime.cpp index 36a97db159e..2832b9202b4 100644 --- a/stl/src/xtime.cpp +++ b/stl/src/xtime.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// xtime functions +// _timespec64 functions for system time #include #include @@ -12,32 +12,32 @@ constexpr long _Nsec_per_sec = 1000000000L; constexpr long _Nsec_per_msec = 1000000L; constexpr int _Msec_per_sec = 1000; -static void xtime_normalize(xtime* xt) { // adjust so that 0 <= nsec < 1 000 000 000 - while (xt->nsec < 0) { // normalize target time - xt->sec -= 1; - xt->nsec += _Nsec_per_sec; +static void _timespec64_normalize(_timespec64* xt) { // adjust so that 0 <= tv_nsec < 1 000 000 000 + while (xt->tv_nsec < 0) { // normalize target time + xt->tv_sec -= 1; + xt->tv_nsec += _Nsec_per_sec; } - while (_Nsec_per_sec <= xt->nsec) { // normalize target time - xt->sec += 1; - xt->nsec -= _Nsec_per_sec; + while (_Nsec_per_sec <= xt->tv_nsec) { // normalize target time + xt->tv_sec += 1; + xt->tv_nsec -= _Nsec_per_sec; } } -static xtime xtime_diff(const xtime* xt, - const xtime* now) { // return xtime object holding difference between xt and now, treating negative difference as 0 - xtime diff = *xt; - xtime_normalize(&diff); - if (diff.nsec < now->nsec) { // avoid underflow - diff.sec -= now->sec + 1; - diff.nsec += _Nsec_per_sec - now->nsec; +// return _timespec64 object holding difference between xt and now, treating negative difference as 0 +static _timespec64 _timespec64_diff(const _timespec64* xt, const _timespec64* now) { + _timespec64 diff = *xt; + _timespec64_normalize(&diff); + if (diff.tv_nsec < now->tv_nsec) { // avoid underflow + diff.tv_sec -= now->tv_sec + 1; + diff.tv_nsec += _Nsec_per_sec - now->tv_nsec; } else { // no underflow - diff.sec -= now->sec; - diff.nsec -= now->nsec; + diff.tv_sec -= now->tv_sec; + diff.tv_nsec -= now->tv_nsec; } - if (diff.sec < 0 || (diff.sec == 0 && diff.nsec <= 0)) { // time is zero - diff.sec = 0; - diff.nsec = 0; + if (diff.tv_sec < 0 || (diff.tv_sec == 0 && diff.tv_nsec <= 0)) { // time is zero + diff.tv_sec = 0; + diff.tv_nsec = 0; } return diff; } @@ -54,30 +54,31 @@ _CRTIMP2_PURE long long __cdecl _Xtime_get_ticks() { // get system time in 100-n } // Used by several src files, but not dllexported. -void _Xtime_get2(xtime* xt) { // get system time with nanosecond resolution +void _Timespec64_get_sys(_timespec64* xt) { // get system time with nanosecond resolution unsigned long long now = _Xtime_get_ticks(); - xt->sec = static_cast<__time64_t>(now / _Nsec100_per_sec); - xt->nsec = static_cast(now % _Nsec100_per_sec) * 100; + xt->tv_sec = static_cast<__time64_t>(now / _Nsec100_per_sec); + xt->tv_nsec = static_cast(now % _Nsec100_per_sec) * 100; } -_CRTIMP2_PURE long __cdecl _Xtime_diff_to_millis2(const xtime* xt1, const xtime* xt2) { // convert time to milliseconds - xtime diff = xtime_diff(xt1, xt2); - return static_cast(diff.sec * _Msec_per_sec + (diff.nsec + _Nsec_per_msec - 1) / _Nsec_per_msec); +// convert time to milliseconds +_CRTIMP2_PURE long __cdecl _Xtime_diff_to_millis2(const _timespec64* xt1, const _timespec64* xt2) { + _timespec64 diff = _timespec64_diff(xt1, xt2); + return static_cast(diff.tv_sec * _Msec_per_sec + (diff.tv_nsec + _Nsec_per_msec - 1) / _Nsec_per_msec); } // TRANSITION, ABI: preserved for binary compatibility -_CRTIMP2_PURE long __cdecl _Xtime_diff_to_millis(const xtime* xt) { // convert time to milliseconds - xtime now; - _Xtime_get2(&now); +_CRTIMP2_PURE long __cdecl _Xtime_diff_to_millis(const _timespec64* xt) { // convert time to milliseconds + _timespec64 now; + _Timespec64_get_sys(&now); return _Xtime_diff_to_millis2(xt, &now); } // TRANSITION, ABI: preserved for binary compatibility -_CRTIMP2_PURE int __cdecl xtime_get(xtime* xt, int type) { // get current time +_CRTIMP2_PURE int __cdecl xtime_get(_timespec64* xt, int type) { // get current time if (type != TIME_UTC || xt == nullptr) { type = 0; } else { - _Xtime_get2(xt); + _Timespec64_get_sys(xt); } return type; diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 2d41f7f11b8..a1fe83c5569 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -81,6 +81,10 @@ std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_deallocate_ma # Too many constexpr operations std/utilities/charconv/charconv.to.chars/integral.pass.cpp FAIL +std/utilities/template.bitset/bitset.members/left_shift_eq.pass.cpp FAIL +std/utilities/template.bitset/bitset.members/op_and_eq.pass.cpp FAIL +std/utilities/template.bitset/bitset.members/op_or_eq.pass.cpp FAIL +std/utilities/template.bitset/bitset.members/right_shift_eq.pass.cpp FAIL # libc++ tests strengthened assignment operators (not compatible with P2165R4: "Compatibility Between tuple, pair, And tuple-like Objects") std/utilities/tuple/tuple.tuple/tuple.assign/const_pair.pass.cpp FAIL @@ -120,11 +124,27 @@ std/language.support/support.limits/support.limits.general/format.version.compil # libc++ doesn't implement LWG-3670 std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass.cpp FAIL +# libc++ doesn't implement LWG-3836 +std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp FAIL + # libc++ doesn't implement LWG-3857 std/strings/string.view/string.view.cons/from_range.pass.cpp FAIL std/strings/string.view/string.view.cons/from_string1.compile.fail.cpp FAIL std/strings/string.view/string.view.cons/from_string2.compile.fail.cpp FAIL +# libc++ doesn't implement LWG-3870 +std/utilities/memory/specialized.algorithms/specialized.construct/ranges_construct_at.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct_n.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy_n.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.fill/ranges_uninitialized_fill.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.fill.n/ranges_uninitialized_fill_n.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp FAIL + # libc++ doesn't implement P1957R2 "Converting from `T*` to `bool` should be considered narrowing" std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp FAIL std/utilities/variant/variant.variant/variant.assign/T.pass.cpp FAIL @@ -919,13 +939,6 @@ std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put. # Not analyzed. These tests use characters that cannot be represented in legacy character encodings std/utilities/format/format.functions/ascii.pass.cpp FAIL -# Not analyzed. "constexpr evaluation hit maximum step limit; possible infinite loop?" -std/utilities/template.bitset/bitset.members/left_shift_eq.pass.cpp FAIL -std/utilities/template.bitset/bitset.members/op_and_eq.pass.cpp FAIL -std/utilities/template.bitset/bitset.members/op_or_eq.pass.cpp FAIL -std/utilities/template.bitset/bitset.members/right_shift_eq.pass.cpp FAIL -std/utilities/template.bitset/bitset.members/to_string.pass.cpp:1 FAIL - # Not analyzed std/algorithms/alg.modifying.operations/alg.random.sample/ranges_sample.pass.cpp FAIL std/algorithms/alg.modifying.operations/alg.rotate/ranges_rotate.pass.cpp FAIL diff --git a/tests/std/test.lst b/tests/std/test.lst index 1a916d8d640..ccede7b159a 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -174,6 +174,7 @@ tests\GH_000690_overaligned_function tests\GH_000890_pow_template tests\GH_000935_complex_numerical_accuracy tests\GH_000940_missing_valarray_copy +tests\GH_000952_bind_constraints tests\GH_000990_any_link_without_exceptions tests\GH_001001_random_rejection_rounding tests\GH_001010_filesystem_error_encoding @@ -199,6 +200,7 @@ tests\GH_002045_put_time_changes_errno tests\GH_002058_debug_iterator_race tests\GH_002120_streambuf_seekpos_and_seekoff tests\GH_002168_regex_overflow +tests\GH_002206_unreserved_names tests\GH_002299_implicit_sfinae_constraints tests\GH_002307_usual_scope_guard tests\GH_002334_branchless_clamp diff --git a/tests/std/tests/Dev11_0920385_list_sort_allocator/test.cpp b/tests/std/tests/Dev11_0920385_list_sort_allocator/test.cpp index e3b01dad3f4..40e289d093b 100644 --- a/tests/std/tests/Dev11_0920385_list_sort_allocator/test.cpp +++ b/tests/std/tests/Dev11_0920385_list_sort_allocator/test.cpp @@ -282,7 +282,9 @@ int main() { test_1119194(); test_1184701(); test_LWG_2455(); +#if !_HAS_CXX20 // support removed in C++20 by P0619R4 test_allocator_construct_const(); +#endif // !_HAS_CXX20 } // Also test DevDiv-1119194 "The STL should handle allocators that aren't assignable". @@ -465,6 +467,7 @@ void test_LWG_2455() { } } +#if !_HAS_CXX20 // support removed in C++20 by P0619R4 void test_allocator_construct_const() { // Annex D actually requires the default allocator to const_cast here // See N4659 D.9 [depr.default.allocator]/6 @@ -476,3 +479,4 @@ void test_allocator_construct_const() { allocator_traits>::construct(alloc, exampleCptr, 1729); assert(example == 1729); } +#endif // !_HAS_CXX20 diff --git a/tests/std/tests/GH_000431_copy_move_family/test.cpp b/tests/std/tests/GH_000431_copy_move_family/test.cpp index f3f135b5466..9486d75d7f6 100644 --- a/tests/std/tests/GH_000431_copy_move_family/test.cpp +++ b/tests/std/tests/GH_000431_copy_move_family/test.cpp @@ -639,41 +639,6 @@ void test_algorithms(CopyFn copy_fn) { } } -template -void test_uninitialized_algorithms(CopyFn copy_fn) { - test_algorithms(copy_fn); - - { // Test const destination - int src[10] = {5, 7, 3, 4, 6, 4, 7, 1, 9, 5}; - int expected[10] = {5, 7, 3, 4, 6, 4, 7, 1, 9, 5}; - int dst[10]{}; - - copy_fn(begin(src), end(src), cbegin(dst)); - - assert(equal(begin(expected), end(expected), begin(dst), end(dst))); - } - - { // Test move_iterator with const destination - int src[10] = {5, 7, 3, 4, 6, 4, 7, 1, 9, 5}; - int expected[10] = {5, 7, 3, 4, 6, 4, 7, 1, 9, 5}; - int dst[10]{}; - - copy_fn(make_move_iterator(begin(src)), make_move_iterator(end(src)), cbegin(dst)); - - assert(equal(begin(expected), end(expected), begin(dst), end(dst))); - } - - { // Test vector with const destination - vector src = {3, 6, 4, 7, 3}; - vector expected = {3, 6, 4, 7, 3}; - vector dst = {0, 0, 0, 0, 0}; - - copy_fn(begin(src), end(src), cbegin(dst)); - - assert(equal(begin(expected), end(expected), begin(dst), end(dst))); - } -} - int main() { test_algorithms([](auto begin, auto end, auto out) { copy(begin, end, out); }); test_algorithms([](auto begin, auto end, auto out) { copy_n(begin, distance(begin, end), out); }); @@ -682,14 +647,12 @@ int main() { test_algorithms([](auto begin, auto end, auto out) { move(begin, end, out); }); test_algorithms([](auto begin, auto end, auto out) { move_backward(begin, end, next(out, distance(begin, end))); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { uninitialized_copy(begin, end, out); }); - test_uninitialized_algorithms( - [](auto begin, auto end, auto out) { uninitialized_copy_n(begin, distance(begin, end), out); }); + test_algorithms([](auto begin, auto end, auto out) { uninitialized_copy(begin, end, out); }); + test_algorithms([](auto begin, auto end, auto out) { uninitialized_copy_n(begin, distance(begin, end), out); }); #if _HAS_CXX17 - test_uninitialized_algorithms([](auto begin, auto end, auto out) { uninitialized_move(begin, end, out); }); - test_uninitialized_algorithms( - [](auto begin, auto end, auto out) { uninitialized_move_n(begin, distance(begin, end), out); }); + test_algorithms([](auto begin, auto end, auto out) { uninitialized_move(begin, end, out); }); + test_algorithms([](auto begin, auto end, auto out) { uninitialized_move_n(begin, distance(begin, end), out); }); #endif // _HAS_CXX17 #ifdef __cpp_lib_concepts @@ -714,35 +677,35 @@ int main() { } }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_copy(begin, end, out, next(out, distance(begin, end))); }); - test_uninitialized_algorithms( + test_algorithms( [](auto begin, auto end, auto out) { ranges::uninitialized_copy(begin, end, out, unreachable_sentinel); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_copy(begin, unreachable_sentinel, out, next(out, distance(begin, end))); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_copy_n(begin, distance(begin, end), out, next(out, distance(begin, end))); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_copy_n(begin, distance(begin, end), out, unreachable_sentinel); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_move(begin, end, out, next(out, distance(begin, end))); }); - test_uninitialized_algorithms( + test_algorithms( [](auto begin, auto end, auto out) { ranges::uninitialized_move(begin, end, out, unreachable_sentinel); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_move(begin, unreachable_sentinel, out, next(out, distance(begin, end))); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_move_n(begin, distance(begin, end), out, next(out, distance(begin, end))); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_move_n(begin, distance(begin, end), out, unreachable_sentinel); }); #endif // __cpp_lib_concepts diff --git a/tests/std/tests/GH_000952_bind_constraints/env.lst b/tests/std/tests/GH_000952_bind_constraints/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_000952_bind_constraints/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp b/tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp new file mode 100644 index 00000000000..910117a97f3 --- /dev/null +++ b/tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +using namespace std; + +void test() { // COMPILE-ONLY + { + auto lambda = [](int) {}; + auto f = bind(lambda, placeholders::_1); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(is_convertible_v>); + STATIC_ASSERT(!is_convertible_v>); + } + { + auto lambda = [](int) { return 42; }; + auto f = bind(lambda, placeholders::_1); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(is_convertible_v>); + STATIC_ASSERT(!is_convertible_v>); + } + { + auto lambda = [](int) { return 42; }; + auto f = bind(lambda, placeholders::_1); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(is_convertible_v>); + STATIC_ASSERT(is_convertible_v>); + } + { + auto lambda0 = [](int, int) { return true; }; + auto lambda1 = [](const char*) { return 0; }; + auto f = bind(lambda0, placeholders::_1, bind(lambda1, placeholders::_2)); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(is_convertible_v>); + STATIC_ASSERT(is_convertible_v>); + } +} diff --git a/tests/std/tests/GH_002206_unreserved_names/env.lst b/tests/std/tests/GH_002206_unreserved_names/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_002206_unreserved_names/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_002206_unreserved_names/test.compile.pass.cpp b/tests/std/tests/GH_002206_unreserved_names/test.compile.pass.cpp new file mode 100644 index 00000000000..fbd1149a46d --- /dev/null +++ b/tests/std/tests/GH_002206_unreserved_names/test.compile.pass.cpp @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#define nsec delete +#define sec delete +#define xtime delete +#define xtime_get delete + +#include <__msvc_all_public_headers.hpp> diff --git a/tests/std/tests/GH_002992_unwrappable_iter_sent_pairs/test.compile.pass.cpp b/tests/std/tests/GH_002992_unwrappable_iter_sent_pairs/test.compile.pass.cpp index 8dca4b4a419..f038142c6df 100644 --- a/tests/std/tests/GH_002992_unwrappable_iter_sent_pairs/test.compile.pass.cpp +++ b/tests/std/tests/GH_002992_unwrappable_iter_sent_pairs/test.compile.pass.cpp @@ -29,7 +29,10 @@ void test_algorithms(Rng& rng) { (void) ranges::mismatch(rng, other); (void) ranges::mismatch(other, rng); - if constexpr (is_lvalue_reference_v> && ranges::forward_range) { + using range_ref_t = ranges::range_reference_t; + using range_deref_t = remove_reference_t; + if constexpr (is_lvalue_reference_v && !is_const_v && !is_volatile_v + && ranges::forward_range) { (void) ranges::uninitialized_copy(rng.begin(), rng.end(), other.begin(), other.end()); (void) ranges::uninitialized_copy(other.begin(), other.end(), rng.begin(), rng.end()); (void) ranges::uninitialized_copy(rng, other); diff --git a/tests/std/tests/P0088R3_variant/test.cpp b/tests/std/tests/P0088R3_variant/test.cpp index 7c71757d6cf..7471255c69c 100644 --- a/tests/std/tests/P0088R3_variant/test.cpp +++ b/tests/std/tests/P0088R3_variant/test.cpp @@ -7193,7 +7193,8 @@ namespace msvc { using std::variant::variant; }; - my_variant v1{42}, v2{3.14}; + my_variant v1{42}; + my_variant v2{3.14}; auto visitor1 = [](auto&& x) { return static_cast(x); }; assert(std::visit(visitor1, v1) == 42.0); assert(std::visit(visitor1, v2) == 3.14); @@ -7850,6 +7851,92 @@ namespace msvc { #endif // _HAS_CXX20 } } // namespace gh2770 + + namespace assign_cv { + template + struct TypeIdentityImpl { + using type = T; + }; + template + using TypeIdentity = typename TypeIdentityImpl::type; + + struct CvAssignable { + CvAssignable() = default; + CvAssignable(const CvAssignable&) = default; + CvAssignable(CvAssignable&&) = default; + CvAssignable& operator=(const CvAssignable&) = default; + CvAssignable& operator=(CvAssignable&&) = default; + + template + CvAssignable(const volatile TypeIdentity&) noexcept {} + template + CvAssignable(const volatile TypeIdentity&&) noexcept {} + + template + constexpr CvAssignable& operator=(const volatile TypeIdentity&) noexcept { + return *this; + } + template + constexpr CvAssignable& operator=(const volatile TypeIdentity&&) noexcept { + return *this; + } + + template + constexpr const volatile CvAssignable& operator=(const volatile TypeIdentity&) const volatile noexcept { + return *this; + } + template + constexpr const volatile CvAssignable& operator=(const volatile TypeIdentity&&) const volatile noexcept { + return *this; + } + }; + + void run_test() { + using std::swap; + { + std::variant oc{}; + oc.emplace<0>(0); + STATIC_ASSERT(!std::is_copy_assignable_v); + STATIC_ASSERT(!std::is_move_assignable_v); + STATIC_ASSERT(!std::is_swappable_v); + + std::variant ov{}; + std::variant ov2{}; + ov.emplace<0>(0); + swap(ov, ov); + ov = ov2; + ov = std::move(ov2); + + std::variant ocv{}; + ocv.emplace<0>(0); + STATIC_ASSERT(!std::is_copy_assignable_v); + STATIC_ASSERT(!std::is_move_assignable_v); + STATIC_ASSERT(!std::is_swappable_v); + } + { + std::variant oc{}; + std::variant oc2{}; + oc.emplace<0>(CvAssignable{}); + swap(oc, oc); + oc = oc2; + oc = std::move(oc2); + + std::variant ov{}; + std::variant ov2{}; + ov.emplace<0>(CvAssignable{}); + swap(ov, ov); + ov = ov2; + ov = std::move(ov2); + + std::variant ocv{}; + std::variant ocv2{}; + ocv.emplace<0>(CvAssignable{}); + swap(ocv, ocv); + ocv = ocv2; + ocv = std::move(ocv2); + } + } + } // namespace assign_cv } // namespace msvc int main() { @@ -7916,6 +8003,7 @@ int main() { msvc::vso492097::run_test(); msvc::DevCom1031281::run_test(); msvc::gh2770::run_test(); + msvc::assign_cv::run_test(); } #else // ^^^ not x86 or not /analyze / x86 /analyze vvv int main() {} diff --git a/tests/std/tests/P0220R1_optional/test.cpp b/tests/std/tests/P0220R1_optional/test.cpp index 77d3497fde1..9d760fe8ed2 100644 --- a/tests/std/tests/P0220R1_optional/test.cpp +++ b/tests/std/tests/P0220R1_optional/test.cpp @@ -8148,6 +8148,30 @@ namespace msvc { STATIC_ASSERT(!is_constructible_v); } // namespace lwg2842 + namespace lwg3836 { + STATIC_ASSERT(std::is_convertible_v, std::optional>); + STATIC_ASSERT(std::is_convertible_v&, std::optional>); + +#if _HAS_CXX20 +#define CONSTEXPR20 constexpr +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +#define CONSTEXPR20 inline +#endif // ^^^ !_HAS_CXX20 ^^^ + CONSTEXPR20 bool run_test() { + std::optional oi = 0; + std::optional ob = oi; + assert(!ob.value()); + assert(!std::optional{std::optional{0}}.value()); + + return true; + } +#undef CONSTEXPR20 + +#if _HAS_CXX20 + STATIC_ASSERT(run_test()); +#endif // _HAS_CXX20 + } // namespace lwg3836 + namespace vso406124 { // Defend against regression of VSO-406124 void run_test() { @@ -8237,6 +8261,92 @@ namespace msvc { testMove(); } } // namespace gh2458 + + namespace assign_cv { + template + struct TypeIdentityImpl { + using type = T; + }; + template + using TypeIdentity = typename TypeIdentityImpl::type; + + struct CvAssignable { + CvAssignable() = default; + CvAssignable(const CvAssignable&) = default; + CvAssignable(CvAssignable&&) = default; + CvAssignable& operator=(const CvAssignable&) = default; + CvAssignable& operator=(CvAssignable&&) = default; + + template + CvAssignable(const volatile TypeIdentity&) noexcept {} + template + CvAssignable(const volatile TypeIdentity&&) noexcept {} + + template + constexpr CvAssignable& operator=(const volatile TypeIdentity&) noexcept { + return *this; + } + template + constexpr CvAssignable& operator=(const volatile TypeIdentity&&) noexcept { + return *this; + } + + template + constexpr const volatile CvAssignable& operator=(const volatile TypeIdentity&) const volatile noexcept { + return *this; + } + template + constexpr const volatile CvAssignable& operator=(const volatile TypeIdentity&&) const volatile noexcept { + return *this; + } + }; + + void run_test() { + using std::swap; + { + std::optional oc{}; + oc.emplace(0); + STATIC_ASSERT(!std::is_copy_assignable_v); + STATIC_ASSERT(!std::is_move_assignable_v); + STATIC_ASSERT(!std::is_swappable_v); + + std::optional ov{}; + std::optional ov2{}; + ov.emplace(0); + swap(ov, ov); + ov = ov2; + ov = std::move(ov2); + + std::optional ocv{}; + ocv.emplace(0); + STATIC_ASSERT(!std::is_copy_assignable_v); + STATIC_ASSERT(!std::is_move_assignable_v); + STATIC_ASSERT(!std::is_swappable_v); + } + { + std::optional oc{}; + std::optional oc2{}; + oc.emplace(CvAssignable{}); + swap(oc, oc); + oc = oc2; + oc = std::move(oc2); + + std::optional ov{}; + std::optional ov2{}; + ov.emplace(CvAssignable{}); + swap(ov, ov); + ov = ov2; + ov = std::move(ov2); + + std::optional ocv{}; + std::optional ocv2{}; + ocv.emplace(CvAssignable{}); + swap(ocv, ocv); + ocv = ocv2; + ocv = std::move(ocv2); + } + } + } // namespace assign_cv } // namespace msvc int main() { @@ -8334,9 +8444,13 @@ int main() { nonmembers::make_optional_explicit_init_list::run_test(); nonmembers::swap_::run_test(); + msvc::lwg3836::run_test(); + msvc::vso406124::run_test(); msvc::vso508126::run_test(); msvc::vso614907::run_test(); msvc::gh2458::run_test(); + + msvc::assign_cv::run_test(); } diff --git a/tests/std/tests/P0323R12_expected/test.cpp b/tests/std/tests/P0323R12_expected/test.cpp index 14bfc85b158..546077a1ea5 100644 --- a/tests/std/tests/P0323R12_expected/test.cpp +++ b/tests/std/tests/P0323R12_expected/test.cpp @@ -662,6 +662,14 @@ namespace test_expected { test_constructors(); test_constructors(); test_constructors(); + + // LWG-3836 + struct BaseError {}; + struct DerivedError : BaseError {}; + + std::expected e1(false); + std::expected e2(e1); + assert(!e2.value()); } template constexpr bool construct_at_noexcept() { - constexpr bool result = noexcept(construct_at(declval(), declval()...)); - static_assert(noexcept(ranges::construct_at(declval(), declval()...)) == result); - return result; + if constexpr (can_construct_at) { + constexpr bool result = noexcept(construct_at(declval(), declval()...)); + static_assert(noexcept(ranges::construct_at(declval(), declval()...)) == result); + return result; + } else { + return false; + } } template @@ -62,7 +66,11 @@ inline constexpr bool can_construct_at = can_construct_at_impl constexpr bool construct_at_noexcept() { - return noexcept(construct_at(declval(), declval()...)); + if constexpr (can_construct_at) { + return noexcept(construct_at(declval(), declval()...)); + } else { + return false; + } } template @@ -72,17 +80,18 @@ constexpr bool destroy_at_noexcept() { #endif // __cpp_lib_concepts static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); +// per LWG-3888 +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); struct X {}; @@ -100,9 +109,10 @@ struct indestructible { }; static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); +// per LWG-3888 +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); static_assert(can_construct_at); static_assert(can_construct_at); @@ -118,11 +128,13 @@ static_assert(!can_construct_at); // The following static_asserts test our strengthening of noexcept static_assert(construct_at_noexcept()); -static_assert(construct_at_noexcept()); -static_assert(construct_at_noexcept()); -static_assert(construct_at_noexcept()); +// per LWG-3888 +static_assert(!construct_at_noexcept()); +static_assert(!construct_at_noexcept()); +static_assert(!construct_at_noexcept()); static_assert(!construct_at_noexcept()); +// per LWG-3888 static_assert(!construct_at_noexcept()); static_assert(!construct_at_noexcept()); static_assert(!construct_at_noexcept()); @@ -173,20 +185,6 @@ void test_runtime(const Ty& val) { assert(*asPtrTy == val); ranges::destroy_at(asPtrTy); #endif // __cpp_lib_concepts - - // test voidify: - const auto asCv = static_cast(asPtrTy); - memset(storage, 42, sizeof(Ty)); - assert(asPtrTy == construct_at(asCv, val)); - assert(const_cast(*asCv) == val); - destroy_at(asCv); - -#ifdef __cpp_lib_concepts - memset(storage, 42, sizeof(Ty)); - assert(asPtrTy == ranges::construct_at(asCv, val)); - assert(const_cast(*asCv) == val); - ranges::destroy_at(asCv); -#endif // __cpp_lib_concepts } template @@ -195,21 +193,20 @@ void test_array(const T& val) { (void) val; alignas(T) unsigned char storage[sizeof(T) * N]; - using U = conditional_t, const volatile T, T>; - const auto ptr = reinterpret_cast(storage); + const auto ptr = reinterpret_cast(storage); for (auto i = 0; i < N; ++i) { construct_at(ptr + i, val); } - destroy_at(reinterpret_cast(ptr)); + destroy_at(reinterpret_cast(ptr)); #ifdef __cpp_lib_concepts for (auto i = 0; i < N; ++i) { ranges::construct_at(ptr + i, val); } - ranges::destroy_at(reinterpret_cast(ptr)); + ranges::destroy_at(reinterpret_cast(ptr)); #endif // __cpp_lib_concepts } @@ -522,6 +519,114 @@ constexpr void test_compiletime_operators() { } static_assert((test_compiletime_operators(), true)); +#ifdef __cpp_lib_concepts +// Also test LWG-3888 Most ranges uninitialized memory algorithms are underconstrained +template +concept CanUninitializedDefaultConstruct = requires(Rng& r) { ranges::uninitialized_default_construct(r); }; + +template +concept CanUninitializedDefaultConstructN = + requires(It&& i) { ranges::uninitialized_default_construct_n(forward(i), iter_difference_t{}); }; + +template +concept CanUninitializedValueConstruct = requires(Rng& r) { ranges::uninitialized_value_construct(r); }; + +template +concept CanUninitializedValueConstructN = + requires(It&& i) { ranges::uninitialized_value_construct_n(forward(i), iter_difference_t{}); }; + +template +concept CanUninitializedFill = requires(Rng& r, const T& t) { ranges::uninitialized_fill(r, t); }; + +template +concept CanUninitializedFillN = + requires(It&& i, const T& t) { ranges::uninitialized_fill_n(forward(i), iter_difference_t{}, t); }; + +template +concept CanUninitializedCopy = requires(InRng& ri, OutRng& ro) { ranges::uninitialized_copy(ri, ro); }; + +template +concept CanUninitializedCopyN = + requires(InIt&& ii, OutIt&& io, S&& s) { + ranges::uninitialized_copy_n(forward(ii), iter_difference_t{}, forward(io), forward(s)); + }; + +template +concept CanUninitializedMove = requires(InRng& ri, OutRng& ro) { ranges::uninitialized_move(ri, ro); }; + +template +concept CanUninitializedMoveN = + requires(InIt&& ii, OutIt&& io, S&& s) { + ranges::uninitialized_move_n(forward(ii), iter_difference_t{}, forward(io), forward(s)); + }; + +template +concept CanDestroy = requires(Rng&& r) { ranges::destroy(forward(r)); }; + +template +concept CanDestroyN = requires(It&& i) { ranges::destroy_n(forward(i), iter_difference_t{}); }; + +static_assert(CanUninitializedDefaultConstruct); +static_assert(!CanUninitializedDefaultConstruct); +static_assert(!CanUninitializedDefaultConstruct); +static_assert(!CanUninitializedDefaultConstruct); + +static_assert(CanUninitializedDefaultConstructN); +static_assert(!CanUninitializedDefaultConstructN); +static_assert(!CanUninitializedDefaultConstructN); +static_assert(!CanUninitializedDefaultConstructN); + +static_assert(CanUninitializedValueConstruct); +static_assert(!CanUninitializedValueConstruct); +static_assert(!CanUninitializedValueConstruct); +static_assert(!CanUninitializedValueConstruct); + +static_assert(CanUninitializedValueConstructN); +static_assert(!CanUninitializedValueConstructN); +static_assert(!CanUninitializedValueConstructN); +static_assert(!CanUninitializedValueConstructN); + +static_assert(CanUninitializedFill); +static_assert(!CanUninitializedFill); +static_assert(!CanUninitializedFill); +static_assert(!CanUninitializedFill); + +static_assert(CanUninitializedFillN); +static_assert(!CanUninitializedFillN); +static_assert(!CanUninitializedFillN); +static_assert(!CanUninitializedFillN); + +static_assert(CanUninitializedCopy); +static_assert(!CanUninitializedCopy); +static_assert(!CanUninitializedCopy); +static_assert(!CanUninitializedCopy); + +static_assert(CanUninitializedCopyN); +static_assert(!CanUninitializedCopyN); +static_assert(!CanUninitializedCopyN); +static_assert(!CanUninitializedCopyN); + +static_assert(CanUninitializedMove); +static_assert(!CanUninitializedMove); +static_assert(!CanUninitializedMove); +static_assert(!CanUninitializedMove); + +static_assert(CanUninitializedMoveN); +static_assert(!CanUninitializedMoveN); +static_assert(!CanUninitializedMoveN); +static_assert(!CanUninitializedMoveN); + +static_assert(CanDestroy); +static_assert(!CanDestroy); +static_assert(!CanDestroy); +static_assert(!CanDestroy); + +static_assert(CanDestroyN); +static_assert(!CanDestroyN); +static_assert(!CanDestroyN); +static_assert(!CanDestroyN); +#endif // __cpp_lib_concepts + int main() { test_runtime(1234); test_runtime(string("hello world")); diff --git a/tests/std/tests/P0896R4_common_iterator/test.cpp b/tests/std/tests/P0896R4_common_iterator/test.cpp index d1736b99cfd..ac88a54358b 100644 --- a/tests/std/tests/P0896R4_common_iterator/test.cpp +++ b/tests/std/tests/P0896R4_common_iterator/test.cpp @@ -1,6 +1,12 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#pragma warning(disable : 5215) // volatile function arguments are deprecated in C++20 + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wdeprecated-volatile" // volatile function arguments are deprecated in C++20 +#endif // __clang__ + #include #include #include @@ -332,6 +338,84 @@ void test_non_trivially_destructible_type() { // COMPILE-ONLY common_iterator it; } +struct VolatileSentinel { + VolatileSentinel() = default; + VolatileSentinel(const VolatileSentinel&) = default; + VolatileSentinel(VolatileSentinel&&) = default; + VolatileSentinel& operator=(const VolatileSentinel&) = default; + VolatileSentinel& operator=(VolatileSentinel&&) = default; + + constexpr explicit VolatileSentinel(const char* p) noexcept : ptr_{p} {} + + template + constexpr VolatileSentinel(const volatile type_identity_t& other) noexcept : ptr_{other.ptr_} {} + template + constexpr VolatileSentinel(const volatile type_identity_t&& other) noexcept : ptr_{other.ptr_} {} + + template + VolatileSentinel& operator=(volatile type_identity_t& rhs) noexcept { + ptr_ = rhs.ptr_; + return *this; + } + template + VolatileSentinel& operator=(volatile type_identity_t&& rhs) noexcept { + ptr_ = rhs.ptr_; + return *this; + } + template + VolatileSentinel& operator=(const volatile type_identity_t& rhs) noexcept { + ptr_ = rhs.ptr_; + return *this; + } + template + VolatileSentinel& operator=(const volatile type_identity_t&& rhs) noexcept { + ptr_ = rhs.ptr_; + return *this; + } + + template + volatile VolatileSentinel& operator=(const volatile type_identity_t& rhs) volatile noexcept { + ptr_ = rhs.ptr_; + return *this; + } + template + volatile VolatileSentinel& operator=(const volatile type_identity_t&& rhs) volatile noexcept { + ptr_ = rhs.ptr_; + return *this; + } + + friend constexpr bool operator==(const char* const lhs, VolatileSentinel rhs) noexcept { + return lhs == rhs.ptr_; + } + + friend constexpr auto operator-(const char* const lhs, VolatileSentinel rhs) noexcept { + return lhs - rhs.ptr_; + } + + friend constexpr auto operator-(VolatileSentinel lhs, const char* const rhs) noexcept { + return lhs.ptr_ - rhs; + } + + const char* ptr_ = nullptr; +}; + +// constexpr-incompatible +void test_volatile() { + using std::swap; + using CommonIt = common_iterator; + + CommonIt it{static_cast(nullptr)}; + CommonIt se{VolatileSentinel{static_cast(nullptr)}}; + + assert(it == se); + assert(it - se == 0); + assert(se - it == 0); + + swap(it, it); + it = se; + it = move(se); +} + int main() { with_writable_iterators::call(); static_assert(with_writable_iterators::call()); @@ -344,4 +428,6 @@ int main() { test_lwg_3574(); static_assert(test_lwg_3574()); + + test_volatile(); // constexpr-incompatible } diff --git a/tests/std/tests/P0896R4_views_single/test.cpp b/tests/std/tests/P0896R4_views_single/test.cpp index 54fc7abfb7c..2c2ad638519 100644 --- a/tests/std/tests/P0896R4_views_single/test.cpp +++ b/tests/std/tests/P0896R4_views_single/test.cpp @@ -170,6 +170,72 @@ void test_non_trivially_destructible_type() { // COMPILE-ONLY (void) views::single(non_trivially_destructible{}); } +struct VolatileConstructible { + VolatileConstructible() = default; + VolatileConstructible(const VolatileConstructible&) = default; + VolatileConstructible(VolatileConstructible&&) = default; + VolatileConstructible& operator=(const VolatileConstructible&) = default; + VolatileConstructible& operator=(VolatileConstructible&&) = default; + + template + constexpr VolatileConstructible(const volatile type_identity_t&) noexcept {} + template + constexpr VolatileConstructible(const volatile type_identity_t&&) noexcept {} +}; + +struct ConstSelection { + ConstSelection() = default; + ConstSelection(const ConstSelection&) = default; + ConstSelection(ConstSelection&&) = default; + ConstSelection& operator=(const ConstSelection&) = default; + ConstSelection& operator=(ConstSelection&&) = default; + + constexpr explicit ConstSelection(int x) noexcept : value{x} {} + + template + constexpr const ConstSelection& operator=(const type_identity_t&) const noexcept { + return *this; + } + + int value = 0; +}; + +static_assert(is_trivially_copy_assignable_v>); +static_assert(!is_trivially_copy_assignable_v>); + +constexpr bool test_cv() { + { + ranges::single_view sv{}; + ranges::single_view sv2{}; + sv = sv2; + sv = move(sv2); + } + { + ranges::single_view svv{}; + ranges::single_view svv2{}; + svv = svv2; + svv = move(svv2); + } + { + [[maybe_unused]] ranges::single_view svc{}; + [[maybe_unused]] ranges::single_view svcv{}; + } + { + ranges::single_view svx{in_place, 0}; + ranges::single_view svy{in_place, 42}; + svy = svx; + assert(svy.front().value == 0); + } + { + ranges::single_view scvx{in_place, 0}; + ranges::single_view scvy{in_place, 42}; + scvy = scvx; + assert(scvy.front().value == 42); + } + + return true; +} + int main() { static_assert(test_one_type(42, 42)); test_one_type(42, 42); @@ -179,4 +245,7 @@ int main() { test_one_type(only_copy_constructible{42}, 42); test_one_type(string{"Hello, World!"}, "Hello, World!"); + + static_assert(test_cv()); + assert(test_cv()); } diff --git a/tests/std/tests/P1208R6_source_location/header.h b/tests/std/tests/P1208R6_source_location/header.h index fd06b41a199..2bf8cdf2b31 100644 --- a/tests/std/tests/P1208R6_source_location/header.h +++ b/tests/std/tests/P1208R6_source_location/header.h @@ -10,7 +10,11 @@ constexpr void header_test() { using namespace std; const auto x = source_location::current(); assert(x.line() == __LINE__ - 1); +#ifdef __clang__ + assert(x.column() == 20); +#else // ^^^ defined(__clang__) / !defined(__clang__) vvv assert(x.column() == 37); +#endif // ^^^ !defined(__clang__) ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(x.function_name() == "header_test"sv); #else // ^^^ workaround / no workaround vvv diff --git a/tests/std/tests/P1208R6_source_location/test.cpp b/tests/std/tests/P1208R6_source_location/test.cpp index 8711f14e60a..671fc0b33ee 100644 --- a/tests/std/tests/P1208R6_source_location/test.cpp +++ b/tests/std/tests/P1208R6_source_location/test.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#if defined(__cpp_consteval) && !defined(__EDG__) // TRANSITION, VSO-1285779 +#ifndef __EDG__ // TRANSITION, VSO-1285779 #include "header.h" #include #include @@ -19,7 +19,11 @@ constexpr auto test_cpp = "test.cpp"sv; constexpr auto g = source_location::current(); static_assert(g.line() == __LINE__ - 1); +#ifdef __clang__ +static_assert(g.column() == 20); +#else // ^^^ defined(__clang__) / !defined(__clang__) vvv static_assert(g.column() == 37); +#endif // ^^^ !defined(__clang__) ^^^ static_assert(g.function_name() == ""sv); static_assert(string_view{g.file_name()}.ends_with(test_cpp)); @@ -49,7 +53,11 @@ constexpr void copy_test() { constexpr void local_test() { const auto x = source_location::current(); assert(x.line() == __LINE__ - 1); +#ifdef __clang__ + assert(x.column() == 20); +#else // ^^^ defined(__clang__) / !defined(__clang__) vvv assert(x.column() == 37); +#endif // ^^^ !defined(__clang__) ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(x.function_name() == "local_test"sv); #else // ^^^ workaround / no workaround vvv @@ -135,8 +143,13 @@ constexpr void lambda_test() { const auto x2 = l2(); assert(x1.line() == __LINE__ - 4); assert(x2.line() == __LINE__ - 4); +#ifdef __clang__ + assert(x1.column() == 28); + assert(x2.column() == 33); +#else // ^^^ defined(__clang__) / !defined(__clang__) vvv assert(x1.column() == 52); assert(x2.column() == 50); +#endif // ^^^ !defined(__clang__) ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(x1.function_name() == "lambda_test"sv); assert(x2.function_name() == "operator()"sv); @@ -162,7 +175,11 @@ constexpr source_location function_template() { constexpr void function_template_test() { const auto x1 = function_template(); assert(x1.line() == __LINE__ - 5); +#ifdef __clang__ + assert(x1.column() == 12); +#else // ^^^ defined(__clang__) / !defined(__clang__) vvv assert(x1.column() == 29); +#endif // ^^^ !defined(__clang__) ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(x1.function_name() == "function_template"sv); #else // ^^^ workaround / no workaround vvv @@ -184,12 +201,21 @@ constexpr void function_template_test() { constexpr bool test() { copy_test(); local_test(); +#ifndef __clang__ // TRANSITION, LLVM-56379 argument_test(__LINE__, 5); +#endif // __clang__ +#ifdef __clang__ + const auto loc = source_location::current(); + argument_test(__LINE__ - 1, 22, loc); +#else // ^^^ defined(__clang__) / !defined(__clang__) const auto loc = source_location::current(); argument_test(__LINE__ - 1, 39, loc); +#endif // ^^^ !defined(__clang__) ^^^ +#ifndef __clang__ // TRANSITION, LLVM-56379 sloc_constructor_test(); different_constructor_test(); sub_member_test(); +#endif // __clang__ lambda_test(); function_template_test(); header_test(); @@ -207,6 +233,6 @@ int main() { static_assert(test()); return 0; } -#else // ^^^ defined(__cpp_consteval) && !defined(__EDG__) / !defined(__cpp_consteval) || defined(__EDG__) vvv +#else // ^^^ !defined(__EDG__) / defined(__EDG__) vvv int main() {} -#endif // ^^^ !defined(__cpp_consteval) || defined(__EDG__) ^^^ +#endif // ^^^ defined(__EDG__) ^^^ diff --git a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp index 0e6909d701f..e48746e4e1d 100644 --- a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp @@ -1274,7 +1274,8 @@ template void regex_token_iterator_test_impl() { using it_type = typename RegexTokenIterator::value_type::iterator; int submatches[10] = {0}; - it_type start{}, finish{}; + it_type start{}; + it_type finish{}; typename RegexTokenIterator::regex_type rgx{}; RegexTokenIterator rti0(start, finish, rgx, submatches); } diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 83368cba70e..c3e7c998c0e 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -42,13 +42,13 @@ STATIC_ASSERT(__cpp_lib_algorithm_iterator_requirements == 202207L); #endif #endif -#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 +#if _HAS_CXX23 #ifndef __cpp_lib_allocate_at_least #error __cpp_lib_allocate_at_least is not defined -#elif __cpp_lib_allocate_at_least != 202106L -#error __cpp_lib_allocate_at_least is not 202106L +#elif __cpp_lib_allocate_at_least != 202302L +#error __cpp_lib_allocate_at_least is not 202302L #else -STATIC_ASSERT(__cpp_lib_allocate_at_least == 202106L); +STATIC_ASSERT(__cpp_lib_allocate_at_least == 202302L); #endif #else #ifdef __cpp_lib_allocate_at_least @@ -1968,7 +1968,7 @@ STATIC_ASSERT(__cpp_lib_smart_ptr_for_overwrite == 202002L); #endif #endif -#if _HAS_CXX20 && defined(__cpp_consteval) +#if _HAS_CXX20 #ifndef __cpp_lib_source_location #error __cpp_lib_source_location is not defined #elif __cpp_lib_source_location != 201907L diff --git a/tests/std/tests/VSO_0180469_fill_family/test.cpp b/tests/std/tests/VSO_0180469_fill_family/test.cpp index 52bc0a41a5d..d6898732bca 100644 --- a/tests/std/tests/VSO_0180469_fill_family/test.cpp +++ b/tests/std/tests/VSO_0180469_fill_family/test.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include using namespace std; @@ -51,6 +52,19 @@ void test_case_fill(CharT value, Func fillCall) { } } +template +void test_fill_volatile() { + const CharT testCases[] = {cast(-100), cast(-1), cast(0), cast(1), cast(100)}; + + for (CharT testCase : testCases) { + test_case_fill(testCase, + [](BuffT* buff, CharT value, size_t start, size_t end) { fill(buff + start, buff + end, value); }); + + test_case_fill(testCase, + [](BuffT* buff, CharT value, size_t start, size_t end) { fill_n(buff + start, end - start, value); }); + } +} + template void test_fill() { const CharT testCases[] = {cast(-100), cast(-1), cast(0), cast(1), cast(100)}; @@ -133,9 +147,9 @@ int main() { test_fill(); test_fill(); - test_fill(); // Test GH-1183 + test_fill_volatile(); // Test GH-1183 #ifdef __cpp_lib_byte - test_fill(); // Test GH-1556 + test_fill_volatile(); // Test GH-1556 #endif // __cpp_lib_byte test_uninitialized_fill( diff --git a/tests/std/tests/VSO_0226079_mutex/test.cpp b/tests/std/tests/VSO_0226079_mutex/test.cpp index a6ef7a2246a..8224f83f3ae 100644 --- a/tests/std/tests/VSO_0226079_mutex/test.cpp +++ b/tests/std/tests/VSO_0226079_mutex/test.cpp @@ -339,50 +339,6 @@ struct mutex_test_fixture { #endif // TRANSITION, GH-1472 } - // nonstandard xtime type - template - xtime to_xtime(const chrono::duration& rel_time) { // convert duration to xtime - xtime xt; - if (rel_time <= chrono::duration::zero()) { // negative or zero relative time, return zero - xt.sec = 0; - xt.nsec = 0; - } else { // positive relative time, convert - chrono::nanoseconds t0 = chrono::system_clock::now().time_since_epoch(); - t0 += chrono::duration_cast(rel_time); - xt.sec = chrono::duration_cast(t0).count(); - t0 -= chrono::seconds(xt.sec); - xt.nsec = static_cast(t0.count()); - } - return xt; - } - - void test_timed_lockable_xtime() { - assert(time_execution([this] { - const auto xt = to_xtime(24h); - assert(mtx.try_lock_until(&xt)); - }) < 1h); - mtx.unlock(); - assert(time_execution([this] { - const auto xt = to_xtime(24h); - unique_lock ul(mtx, defer_lock); - assert(ul.try_lock_until(&xt)); - }) < 1h); - -#if 0 // TRANSITION, GH-1472 - ot.lock(); - assert(time_execution([this] { - const auto xt = to_xtime(50ms); - assert(!mtx.try_lock_until(&xt)); - }) >= 50ms); - assert(time_execution([this] { - const auto xt = to_xtime(50ms); - unique_lock ul(mtx, defer_lock); - assert(!ul.try_lock_until(&xt)); - }) >= 50ms); - ot.unlock(); -#endif // TRANSITION, GH-1472 - } - void test_recursive_lockable() { mtx.lock(); assert(!ot.try_lock()); @@ -522,7 +478,6 @@ int main() { mutex_test_fixture fixture; fixture.test_lockable(); fixture.test_timed_lockable(); - fixture.test_timed_lockable_xtime(); } { @@ -535,7 +490,6 @@ int main() { mutex_test_fixture fixture; fixture.test_lockable(); fixture.test_timed_lockable(); - fixture.test_timed_lockable_xtime(); fixture.test_recursive_lockable(); }