diff --git a/README.md b/README.md index 56cd3ab20b1..84077532aee 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 [N4981][], which will eventually become the next C++ +We're implementing the latest C++ Working Draft, currently [N4988][], 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 @@ -141,11 +141,15 @@ Just try to follow these rules, so we can spend more time fixing bugs and implem # How To Build With The Visual Studio IDE -1. Install Visual Studio 2022 17.11 Preview 3 or later. +1. Install Visual Studio 2022 17.12 Preview 1 or later. * Select "Windows 11 SDK (10.0.22621.0)" in the VS Installer. + * Select "MSVC v143 - VS 2022 C++ ARM64/ARM64EC build tools (Latest)" in the VS Installer + if you would like to build the ARM64/ARM64EC target. + * Select "MSVC v143 - VS 2022 C++ ARM build tools (Latest)" in the VS Installer + if you would like to build the ARM target. * We recommend selecting "C++ CMake tools for Windows" in the VS Installer. This will ensure that you're using supported versions of CMake and Ninja. - * Otherwise, install [CMake][] 3.29.0 or later, and [Ninja][] 1.11.0 or later. + * Otherwise, install [CMake][] 3.29.0 or later, and [Ninja][] 1.12.1 or later. * Make sure [Python][] 3.12 or later is available to CMake. 2. Open Visual Studio, and choose the "Clone or check out code" option. Enter the URL of this repository, `https://github.com/microsoft/STL`. @@ -156,11 +160,15 @@ Just try to follow these rules, so we can spend more time fixing bugs and implem # How To Build With A Native Tools Command Prompt -1. Install Visual Studio 2022 17.11 Preview 3 or later. +1. Install Visual Studio 2022 17.12 Preview 1 or later. * Select "Windows 11 SDK (10.0.22621.0)" in the VS Installer. + * Select "MSVC v143 - VS 2022 C++ ARM64/ARM64EC build tools (Latest)" in the VS Installer + if you would like to build the ARM64/ARM64EC target. + * Select "MSVC v143 - VS 2022 C++ ARM build tools (Latest)" in the VS Installer + if you would like to build the ARM target. * We recommend selecting "C++ CMake tools for Windows" in the VS Installer. This will ensure that you're using supported versions of CMake and Ninja. - * Otherwise, install [CMake][] 3.29.0 or later, and [Ninja][] 1.11.0 or later. + * Otherwise, install [CMake][] 3.29.0 or later, and [Ninja][] 1.12.1 or later. * Make sure [Python][] 3.12 or later is available to CMake. 2. Open a command prompt. 3. Change directories to a location where you'd like a clone of this STL repository. @@ -180,6 +188,30 @@ To build the x64 target (recommended): 3. `cmake --preset x64` 4. `cmake --build --preset x64` +To build the ARM target: + +1. `"C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Auxiliary\Build\vcvarsall.bat" x64_arm` + * If you installed VS to a non-default location, change this path accordingly. +2. Change directories to the previously cloned `STL` directory. +3. `cmake --preset ARM` +4. `cmake --build --preset ARM` + +To build the ARM64 target: + +1. `"C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Auxiliary\Build\vcvarsall.bat" x64_arm64` + * If you installed VS to a non-default location, change this path accordingly. +2. Change directories to the previously cloned `STL` directory. +3. `cmake --preset ARM64` +4. `cmake --build --preset ARM64` + +To build the ARM64EC target: + +1. `"C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Auxiliary\Build\vcvarsall.bat" x64_arm64` + * If you installed VS to a non-default location, change this path accordingly. +2. Change directories to the previously cloned `STL` directory. +3. `cmake --preset ARM64EC` +4. `cmake --build --preset ARM64EC` + # How To Consume Consumption of the built library is largely based on the build system you're using. There are at least 2 directories @@ -537,7 +569,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/ -[N4981]: https://wg21.link/N4981 +[N4988]: https://wg21.link/N4988 [NOTICE.txt]: NOTICE.txt [Ninja]: https://ninja-build.org [STL-CI-badge]: https://dev.azure.com/vclibs/STL/_apis/build/status%2FSTL-CI?branchName=main "STL-CI" diff --git a/azure-devops/config.yml b/azure-devops/config.yml index a7da64abd9c..af1ef4d88f3 100644 --- a/azure-devops/config.yml +++ b/azure-devops/config.yml @@ -5,7 +5,7 @@ variables: - name: poolName - value: 'StlBuild-2024-07-09T1614-Pool' + value: 'StlBuild-2024-08-14T0018-Pool' readonly: true - name: poolDemands value: 'EnableSpotVM -equals false' diff --git a/azure-devops/provision-image.ps1 b/azure-devops/provision-image.ps1 index 097bc2fd53a..e864be37473 100644 --- a/azure-devops/provision-image.ps1 +++ b/azure-devops/provision-image.ps1 @@ -40,10 +40,10 @@ foreach ($workload in $VisualStudioWorkloads) { } # https://github.com/PowerShell/PowerShell/releases/latest -$PowerShellUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.4.3/PowerShell-7.4.3-win-x64.msi' +$PowerShellUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.4.4/PowerShell-7.4.4-win-x64.msi' $PowerShellArgs = @('/quiet', '/norestart') -$PythonUrl = 'https://www.python.org/ftp/python/3.12.4/python-3.12.4-amd64.exe' +$PythonUrl = 'https://www.python.org/ftp/python/3.12.5/python-3.12.5-amd64.exe' $PythonArgs = @('/quiet', 'InstallAllUsers=1', 'PrependPath=1', 'CompileAll=1', 'Include_doc=0') $CudaUrl = 'https://developer.download.nvidia.com/compute/cuda/12.4.0/local_installers/cuda_12.4.0_551.61_windows.exe' diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 32c6e1925fa..6b71cb76f25 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -62,7 +62,7 @@ endif() set(CMAKE_BUILD_TYPE RelWithDebInfo) # /utf-8 affects . -add_compile_options("$<$:/diagnostics:caret;/W4;/WX;/w14265;/w15038;/w15262;/utf-8>") +add_compile_options("$<$:/diagnostics:caret;/W4;/WX;/w14265;/w15038;/w15262;/utf-8;/Zc:preprocessor>") if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/google-benchmark/.git") message(FATAL_ERROR "google-benchmark is not checked out; make sure to run\n git submodule update --init benchmarks/google-benchmark") diff --git a/benchmarks/google-benchmark b/benchmarks/google-benchmark index a4cf155615c..a6ad7fbbdc2 160000 --- a/benchmarks/google-benchmark +++ b/benchmarks/google-benchmark @@ -1 +1 @@ -Subproject commit a4cf155615c63e019ae549e31703bf367df5b471 +Subproject commit a6ad7fbbdc2e14fab82bb8a6d27760d700198cbf diff --git a/llvm-project b/llvm-project index 12fcca0afeb..1b7631a699e 160000 --- a/llvm-project +++ b/llvm-project @@ -1 +1 @@ -Subproject commit 12fcca0afeb08fbe41d79c5387cfacb249992bb4 +Subproject commit 1b7631a699e6af7f497548a1ceb5be0570c60ed0 diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 790e8065928..d9825b564d8 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -422,7 +422,7 @@ add_compile_definitions(_CRTBLD _VCRT_ALLOW_INTERNALS _HAS_OLD_IOSTREAMS_MEMBERS set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "Embedded") add_compile_options(/WX /Gy - "$<$:/diagnostics:caret;/W4;/w14265;/w15038;/fastfail;/guard:cf;/Zp8;/std:c++latest;/permissive-;/Zc:threadSafeInit-;/Zl>" + "$<$:/diagnostics:caret;/W4;/w14265;/w15038;/fastfail;/guard:cf;/Zp8;/std:c++latest;/permissive-;/Zc:preprocessor;/Zc:threadSafeInit-;/Zl>" "$<$:/W3;/nologo;/quiet>" ) @@ -557,7 +557,7 @@ function(add_stl_dlls D_SUFFIX REL_OR_DBG) generate_satellite_def("atomic_wait" "${D_SUFFIX}") add_library(msvcp${D_SUFFIX}_atomic_wait SHARED "${CMAKE_BINARY_DIR}/msvcp_atomic_wait${D_SUFFIX}.def") - target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib" "synchronization.lib") + target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_atomic_wait${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_atomic_wait${VCLIBS_SUFFIX}") diff --git a/stl/debugger/STL.natvis b/stl/debugger/STL.natvis index 01e8dd606b6..a3d3fb2f1a3 100644 --- a/stl/debugger/STL.natvis +++ b/stl/debugger/STL.natvis @@ -1520,9 +1520,9 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - move_iterator {current} + move_iterator {_Current} - current + _Current @@ -2001,16 +2001,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - - {{ size={size()} }} - - empty() - front() - back() - data() - - - dangling diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 5ef55aded17..acc6ac364be 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -220,42 +220,48 @@ struct _WChar_traits : private _Char_traits<_Elem, unsigned short> { _In_reads_(_Count) const _Elem* const _First2, const size_t _Count) noexcept /* strengthened */ { // compare [_First1, _First1 + _Count) with [_First2, ...) #if _HAS_CXX17 - if constexpr (is_same_v<_Elem, wchar_t>) { - return __builtin_wmemcmp(_First1, _First2, _Count); - } else { - return _Primary_char_traits::compare(_First1, _First2, _Count); + if (_STD _Is_constant_evaluated()) { + if constexpr (is_same_v<_Elem, wchar_t>) { + return __builtin_wmemcmp(_First1, _First2, _Count); + } else { + return _Primary_char_traits::compare(_First1, _First2, _Count); + } } -#else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv +#endif // _HAS_CXX17 + return _CSTD wmemcmp( reinterpret_cast(_First1), reinterpret_cast(_First2), _Count); -#endif // ^^^ !_HAS_CXX17 ^^^ } _NODISCARD static _CONSTEXPR17 size_t length(_In_z_ const _Elem* _First) noexcept /* strengthened */ { // find length of null-terminated sequence #if _HAS_CXX17 - if constexpr (is_same_v<_Elem, wchar_t>) { - return __builtin_wcslen(_First); - } else { - return _Primary_char_traits::length(_First); + if (_STD _Is_constant_evaluated()) { + if constexpr (is_same_v<_Elem, wchar_t>) { + return __builtin_wcslen(_First); + } else { + return _Primary_char_traits::length(_First); + } } -#else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv +#endif // _HAS_CXX17 + return _CSTD wcslen(reinterpret_cast(_First)); -#endif // ^^^ !_HAS_CXX17 ^^^ } _NODISCARD static _CONSTEXPR17 const _Elem* find( _In_reads_(_Count) const _Elem* _First, const size_t _Count, const _Elem& _Ch) noexcept /* strengthened */ { // look for _Ch in [_First, _First + _Count) #if _HAS_CXX17 - if constexpr (is_same_v<_Elem, wchar_t>) { - return __builtin_wmemchr(_First, _Ch, _Count); - } else { - return _Primary_char_traits::find(_First, _Count, _Ch); + if (_STD _Is_constant_evaluated()) { + if constexpr (is_same_v<_Elem, wchar_t>) { + return __builtin_wmemchr(_First, _Ch, _Count); + } else { + return _Primary_char_traits::find(_First, _Count, _Ch); + } } -#else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv +#endif // _HAS_CXX17 + return reinterpret_cast(_CSTD wmemchr(reinterpret_cast(_First), _Ch, _Count)); -#endif // ^^^ !_HAS_CXX17 ^^^ } static _CONSTEXPR20 _Elem* assign( diff --git a/stl/inc/algorithm b/stl/inc/algorithm index af08dfa626b..a0c9712ed3d 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -933,10 +933,8 @@ namespace ranges { _NODISCARD _STATIC_CALL_OPERATOR constexpr bool operator()( _Rng1&& _Range1, _Rng2&& _Range2, _Pr _Pred = {}, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) _CONST_CALL_OPERATOR { if constexpr (sized_range<_Rng1> && sized_range<_Rng2>) { - using _Size1 = _Make_unsigned_like_t>; - const auto _Count = static_cast<_Size1>(_RANGES size(_Range1)); - using _Size2 = _Make_unsigned_like_t>; - if (_Count != static_cast<_Size2>(_RANGES size(_Range2))) { + const auto _Count = _RANGES distance(_Range1); + if (_Count != _RANGES distance(_Range2)) { return false; } return _RANGES _Equal_count(_Ubegin(_Range1), _Ubegin(_Range2), _Count, _STD _Pass_fn(_Pred), @@ -7781,7 +7779,7 @@ namespace ranges { void _Rotate_one_right(_It _First, _It _Mid, _It _Last) { // exchanges the range [_First, _Mid) with [_Mid, _Last) _STL_INTERNAL_CHECK(_RANGES next(_Mid) == _Last); - auto _Temp = _RANGES iter_move(_Mid); + iter_value_t<_It> _Temp(_RANGES iter_move(_Mid)); _RANGES _Move_backward_common(_First, _STD move(_Mid), _STD move(_Last)); *_First = _STD move(_Temp); } @@ -7790,7 +7788,7 @@ namespace ranges { void _Rotate_one_left(_It _First, _It _Mid, _It _Last) { // exchanges the range [_First, _Mid) with [_Mid, _Last) _STL_INTERNAL_CHECK(_RANGES next(_First) == _Mid); - auto _Temp = _RANGES iter_move(_First); + iter_value_t<_It> _Temp(_RANGES iter_move(_First)); auto _Result = _RANGES _Move_unchecked(_STD move(_Mid), _STD move(_Last), _STD move(_First)); *_Result.out = _STD move(_Temp); } @@ -10286,7 +10284,7 @@ namespace ranges { } while (++_UFirst != _ULast) { // process one or two elements - auto _Prev = *_UFirst; + _Vty _Prev(*_UFirst); if (++_UFirst == _ULast) { // process last element if (_STD invoke(_Pred, _STD invoke(_Proj, _Prev), _STD invoke(_Proj, _Found.min))) { _Found.min = _STD move(_Prev); @@ -10723,7 +10721,8 @@ namespace ranges { #endif // _HAS_CXX20 _EXPORT_STD template -_NODISCARD constexpr const _Ty& clamp(const _Ty& _Val, const _Ty& _Min_val, const _Ty& _Max_val, _Pr _Pred) { +_NODISCARD constexpr const _Ty& clamp(const _Ty& _Val _MSVC_LIFETIMEBOUND, const _Ty& _Min_val _MSVC_LIFETIMEBOUND, + const _Ty& _Max_val _MSVC_LIFETIMEBOUND, _Pr _Pred) { // returns _Val constrained to [_Min_val, _Max_val] #if _ITERATOR_DEBUG_LEVEL == 2 if (_DEBUG_LT_PRED(_Pred, _Max_val, _Min_val)) { @@ -10750,7 +10749,8 @@ _NODISCARD constexpr const _Ty& clamp(const _Ty& _Val, const _Ty& _Min_val, cons } _EXPORT_STD template -_NODISCARD constexpr const _Ty& clamp(const _Ty& _Val, const _Ty& _Min_val, const _Ty& _Max_val) { +_NODISCARD constexpr const _Ty& clamp(const _Ty& _Val _MSVC_LIFETIMEBOUND, const _Ty& _Min_val _MSVC_LIFETIMEBOUND, + const _Ty& _Max_val _MSVC_LIFETIMEBOUND) { // returns _Val constrained to [_Min_val, _Max_val] return _STD clamp(_Val, _Min_val, _Max_val, less{}); } @@ -10761,8 +10761,9 @@ namespace ranges { public: template > _Pr = ranges::less> - _NODISCARD _STATIC_CALL_OPERATOR constexpr const _Ty& operator()( - const _Ty& _Val, const _Ty& _Lo, const _Ty& _Hi, _Pr _Pred = {}, _Pj _Proj = {}) _CONST_CALL_OPERATOR { + _NODISCARD _STATIC_CALL_OPERATOR constexpr const _Ty& operator()(const _Ty& _Val _MSVC_LIFETIMEBOUND, + const _Ty& _Lo _MSVC_LIFETIMEBOUND, const _Ty& _Hi _MSVC_LIFETIMEBOUND, _Pr _Pred = {}, + _Pj _Proj = {}) _CONST_CALL_OPERATOR { _STL_ASSERT(!_STD invoke(_Pred, _STD invoke(_Proj, _Hi), _STD invoke(_Proj, _Lo)), "The lower bound cannot be greater than the upper bound in a call to std::ranges::clamp " "(N4950 [alg.clamp]/2)."); diff --git a/stl/inc/array b/stl/inc/array index 8f9b575f8ba..209bd9e95bd 100644 --- a/stl/inc/array +++ b/stl/inc/array @@ -500,7 +500,7 @@ public: return _Elems + _Size; } - _NODISCARD constexpr size_type size() const noexcept { + _NODISCARD _Ret_range_(==, _Size) constexpr size_type size() const noexcept { return _Size; } @@ -528,7 +528,7 @@ public: return _Elems[_Pos]; } - _NODISCARD _CONSTEXPR17 reference operator[](_In_range_(0, _Size - 1) size_type _Pos) noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR17 reference operator[](_In_range_(<, _Size) size_type _Pos) noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pos < _Size, "array subscript out of range"); #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -536,7 +536,7 @@ public: return _Elems[_Pos]; } - _NODISCARD constexpr const_reference operator[](_In_range_(0, _Size - 1) size_type _Pos) const noexcept + _NODISCARD constexpr const_reference operator[](_In_range_(<, _Size) size_type _Pos) const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pos < _Size, "array subscript out of range"); diff --git a/stl/inc/atomic b/stl/inc/atomic index 69bb22d98a7..67582d9b4f7 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -33,18 +33,29 @@ _STL_DISABLE_CLANG_WARNINGS #pragma clang attribute _STD_ATOMIC_HEADER.push([[gnu::target("cx16")]], apply_to = function) #endif // ^^^ defined(__clang__) && defined(_M_X64) ^^^ -// Controls whether ARM64 ldar/ldapr/stlr should be used -#ifndef _STD_ATOMIC_USE_ARM64_LDAR_STLR #if defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_HYBRID_X86_ARM64) -#ifdef __clang__ // TRANSITION, LLVM-62103 -#define _STD_ATOMIC_USE_ARM64_LDAR_STLR 0 -#else // ^^^ Clang doesn't support new intrinsics / __load_acquire/__stlr intrinsics are available vvv #define _STD_ATOMIC_USE_ARM64_LDAR_STLR 1 -#endif // ^^^ __load_acquire/__stlr intrinsics are available ^^^ +#ifdef __clang__ +#define __LOAD_ACQUIRE_ARM64(_Width, _Ptr) \ + static_cast<__int##_Width>(__atomic_load_n(reinterpret_cast(_Ptr), 2)) +#define __STORE_RELEASE(_Width, _Ptr, _Desired) \ + _Compiler_barrier(); \ + __atomic_store_n( \ + reinterpret_cast(_Ptr), static_cast(_Desired), 3) +#else // ^^^ Clang / MSVC vvv +#define __LOAD_ACQUIRE_ARM64(_Width, _Ptr) \ + static_cast<__int##_Width>(__load_acquire##_Width(reinterpret_cast(_Ptr))) +#define __STORE_RELEASE(_Width, _Ptr, _Desired) \ + _Compiler_barrier(); \ + __stlr##_Width( \ + reinterpret_cast(_Ptr), static_cast(_Desired)) +#endif // ^^^ MSVC ^^^ #else // ^^^ ARM64/ARM64EC/HYBRID_X86_ARM64 / Other architectures vvv #define _STD_ATOMIC_USE_ARM64_LDAR_STLR 0 +#define __STORE_RELEASE(_Width, _Ptr, _Desired) \ + _Compiler_or_memory_barrier(); \ + __iso_volatile_store##_Width((_Ptr), (_Desired)) #endif // ^^^ Other architectures ^^^ -#endif // _STD_ATOMIC_USE_ARM64_LDAR_STLR #define ATOMIC_BOOL_LOCK_FREE 2 #define ATOMIC_CHAR_LOCK_FREE 2 @@ -122,9 +133,6 @@ extern "C" inline void _Check_memory_order(const unsigned int _Order) noexcept { #if _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 -#define __LOAD_ACQUIRE_ARM64(_Width, _Ptr) \ - static_cast<__int##_Width>(__load_acquire##_Width(reinterpret_cast(_Ptr))) - #define _ATOMIC_LOAD_ARM64(_Result, _Width, _Ptr, _Order_var) \ switch (_Order_var) { \ case _Atomic_memory_order_relaxed: \ @@ -162,27 +170,12 @@ extern "C" inline void _Check_memory_order(const unsigned int _Order) noexcept { break; \ } -#if _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 - -#define __STORE_RELEASE(_Width, _Ptr, _Desired) \ - _Compiler_barrier(); \ - __stlr##_Width( \ - reinterpret_cast(_Ptr), static_cast(_Desired)); - -#else // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 / _STD_ATOMIC_USE_ARM64_LDAR_STLR == 0 vvv - -#define __STORE_RELEASE(_Width, _Ptr, _Desired) \ - _Compiler_or_memory_barrier(); \ - __iso_volatile_store##_Width((_Ptr), (_Desired)); - -#endif // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR == 0 ^^^ - #define _ATOMIC_STORE_PREFIX(_Width, _Ptr, _Desired) \ case _Atomic_memory_order_relaxed: \ __iso_volatile_store##_Width((_Ptr), (_Desired)); \ return; \ case _Atomic_memory_order_release: \ - __STORE_RELEASE(_Width, _Ptr, _Desired) \ + __STORE_RELEASE(_Width, _Ptr, _Desired); \ return; \ default: \ case _Atomic_memory_order_consume: \ @@ -196,15 +189,9 @@ extern "C" inline void _Check_memory_order(const unsigned int _Order) noexcept { __iso_volatile_store##_Width((_Ptr), (_Desired)); \ _Memory_barrier(); -#if _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 -#define _ATOMIC_STORE_SEQ_CST_ARM64(_Width, _Ptr, _Desired) \ - _Compiler_barrier(); \ - __stlr##_Width( \ - reinterpret_cast(_Ptr), static_cast(_Desired)); \ +#define _ATOMIC_STORE_SEQ_CST_ARM64(_Width, _Ptr, _Desired) \ + __STORE_RELEASE(_Width, _Ptr, _Desired); \ _Memory_barrier(); -#else // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 / _STD_ATOMIC_USE_ARM64_LDAR_STLR == 0 vvv -#define _ATOMIC_STORE_SEQ_CST_ARM64 _ATOMIC_STORE_SEQ_CST_ARM -#endif // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR == 0 ^^^ #define _ATOMIC_STORE_SEQ_CST_X86_X64(_Width, _Ptr, _Desired) (void) _InterlockedExchange##_Width((_Ptr), (_Desired)); #define _ATOMIC_STORE_32_SEQ_CST_X86_X64(_Ptr, _Desired) \ @@ -257,7 +244,11 @@ extern "C" inline void _Atomic_thread_fence(const unsigned int _Order) noexcept _Compiler_barrier(); } #elif defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_HYBRID_X86_ARM64) - _Memory_barrier(); + if (_Order == _Atomic_memory_order_acquire || _Order == _Atomic_memory_order_consume) { + _Memory_load_acquire_barrier(); + } else { + _Memory_barrier(); + } #else // ^^^ ARM32/ARM64/ARM64EC/HYBRID_X86_ARM64 / unsupported hardware vvv #error Unsupported hardware #endif // ^^^ unsupported hardware ^^^ @@ -519,7 +510,7 @@ inline void _Atomic_lock_acquire(long& _Spinlock) noexcept { } } #elif defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_HYBRID_X86_ARM64) - while (_InterlockedExchange(&_Spinlock, 1) != 0) { // TRANSITION, GH-1133: _InterlockedExchange_acq + while (_InterlockedExchange_acq(&_Spinlock, 1) != 0) { while (__iso_volatile_load32(&reinterpret_cast(_Spinlock)) != 0) { __yield(); } @@ -530,15 +521,7 @@ inline void _Atomic_lock_acquire(long& _Spinlock) noexcept { } inline void _Atomic_lock_release(long& _Spinlock) noexcept { -#if (defined(_M_IX86) && !defined(_M_HYBRID_X86_ARM64)) || (defined(_M_X64) && !defined(_M_ARM64EC)) - _InterlockedExchange(&_Spinlock, 0); // TRANSITION, GH-1133: same as ARM -#elif defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_HYBRID_X86_ARM64) - _Memory_barrier(); - __iso_volatile_store32(reinterpret_cast(&_Spinlock), 0); - _Memory_barrier(); // TRANSITION, GH-1133: remove -#else // ^^^ defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_HYBRID_X86_ARM64) ^^^ -#error Unsupported hardware -#endif + __STORE_RELEASE(32, reinterpret_cast(&_Spinlock), 0); } inline void _Atomic_lock_acquire(_Smtx_t* _Spinlock) noexcept { diff --git a/stl/inc/condition_variable b/stl/inc/condition_variable index c72cabc8cbf..2931b1b03f8 100644 --- a/stl/inc/condition_variable +++ b/stl/inc/condition_variable @@ -123,12 +123,26 @@ public: } const auto _Rel_time_ms = _Clamped_rel_time_ms_count(_Rel_time); - const cv_status _Result = _Wait_for_ms_count(_Lck, _Rel_time_ms._Count); - if (_Rel_time_ms._Clamped) { - return cv_status::no_timeout; - } - return _Result; + // wait for signal with timeout + const shared_ptr _Ptr = _Myptr; // for immunity to *this destruction + const auto _Start = _CHRONO steady_clock::now(); + const auto _Target = _Start + _Rel_time; + + unique_lock _Guard{*_Ptr}; + _Unlock_guard<_Lock> _Unlock_outer{_Lck}; + const _Thrd_result _Res = _Cnd_timedwait_for_unchecked(_Mycnd(), _Ptr->_Mymtx(), _Rel_time_ms._Count); + _Guard.unlock(); + + if (_Res == _Thrd_result::_Success) { + return cv_status::no_timeout; // Real or WinAPI-internal spurious wake + } else if (_Rel_time_ms._Clamped) { + return cv_status::no_timeout; // Spuriously wake due to clamped timeout + } else if (_CHRONO steady_clock::now() < _Target) { + return cv_status::no_timeout; // Spuriously wake due to premature timeout + } else { + return cv_status::timeout; + } } template @@ -202,7 +216,7 @@ public: } const unsigned long _Rel_ms_count = _Clamped_rel_time_ms_count(_Abs_time - _Now)._Count; - (void) _Cnd_timedwait_for(_Mycnd(), _Myptr->_Mymtx(), _Rel_ms_count); + (void) _Cnd_timedwait_for_unchecked(_Mycnd(), _Myptr->_Mymtx(), _Rel_ms_count); _Guard_unlocks_before_locking_outer.unlock(); } // relock @@ -223,22 +237,6 @@ private: _NODISCARD _Cnd_t _Mycnd() noexcept { return &_Cnd_storage; } - - template - cv_status _Wait_for_ms_count(_Lock& _Lck, const unsigned int _Rel_ms_count) { - // 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}; - const _Thrd_result _Res = _Cnd_timedwait_for(_Mycnd(), _Ptr->_Mymtx(), _Rel_ms_count); - _Guard.unlock(); - - if (_Res == _Thrd_result::_Success) { - return cv_status::no_timeout; - } else { - return cv_status::timeout; - } - } }; _EXPORT_STD inline void notify_all_at_thread_exit(condition_variable& _Cnd, unique_lock _Lck) noexcept diff --git a/stl/inc/execution b/stl/inc/execution index aef08d6da24..d331de71d60 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -3594,6 +3594,45 @@ _FwdIt partition(_ExPo&&, _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept inline constexpr unsigned char _Local_available = 1; inline constexpr unsigned char _Sum_available = 2; +// For scan algorithms: if the intermediate and output types are the same, we can directly store the binary operation +// result in the output. If not, then we need a place to store intermediate results. +template +constexpr bool _Scan_reuse_output = is_same_v<_Ty, typename iterator_traits<_Iter>::value_type>; + +template > +class _Scan_intermediate_storage { +private: + _Parallel_vector<_Ty> _Data; + +public: + template + explicit _Scan_intermediate_storage(const _Static_partition_team<_Diff>&) noexcept {} + + _NODISCARD _Parallel_vector<_Ty>& operator[](size_t) noexcept { + return _Data; + } +}; + +template +class _Scan_intermediate_storage<_Ty, _Iter, false> { +private: + _Parallel_vector<_Parallel_vector<_Ty>> _Data; + +public: + template + explicit _Scan_intermediate_storage(const _Static_partition_team<_Diff>& _Team) : _Data(_Team._Chunks) { + const auto _Chunk_size = static_cast(_Team._Chunk_size); + for (auto& _Vec : _Data) { + _Vec.reserve(_Chunk_size); + } + } + + _NODISCARD _Parallel_vector<_Ty>& operator[](const size_t _Idx) noexcept { + _STL_INTERNAL_CHECK(_Idx < _Data.size()); + return _Data[_Idx]; + } +}; + template struct _Scan_decoupled_lookback { // inter-chunk communication block in "Single-pass Parallel Prefix Scan with Decoupled Look-back" by Merrill and @@ -3620,7 +3659,8 @@ struct _Scan_decoupled_lookback { } template - void _Apply_exclusive_predecessor(_Ty& _Preceding, _FwdIt _First, const _FwdIt _Last, _BinOp _Reduce_op) { + void _Apply_exclusive_predecessor( + _Ty& _Preceding, _FwdIt _First, _Ty* _First2, const _FwdIt _Last, _BinOp _Reduce_op) { // apply _Preceding to [_First, _Last) and _Sum._Ref(), using _Reduce_op _STD _Implicitly_construct_in_place_by_binary_op(_Sum._Ref(), _Reduce_op, _Preceding, _Local._Ref()); _State.store(_Local_available | _Sum_available); @@ -3628,19 +3668,30 @@ struct _Scan_decoupled_lookback { #pragma loop(ivdep) while (++_First != _Last) { - *_First = _Reduce_op(_Preceding, _STD move(*_First)); + if constexpr (_Scan_reuse_output<_Ty, _FwdIt>) { + *_First = _Reduce_op(_Preceding, _STD move(*_First)); + } else { + ++_First2; + *_First = _Reduce_op(_Preceding, _STD move(*_First2)); + } } } template - void _Apply_inclusive_predecessor(_Ty& _Preceding, _FwdIt _First, const _FwdIt _Last, _BinOp _Reduce_op) { + void _Apply_inclusive_predecessor( + _Ty& _Preceding, _FwdIt _First, _Ty* _First2, const _FwdIt _Last, _BinOp _Reduce_op) { // apply _Preceding to [_First, _Last) and _Sum._Ref(), using _Reduce_op _STD _Implicitly_construct_in_place_by_binary_op(_Sum._Ref(), _Reduce_op, _Preceding, _Local._Ref()); _State.store(_Local_available | _Sum_available); #pragma loop(ivdep) for (; _First != _Last; ++_First) { - *_First = _Reduce_op(_Preceding, _STD move(*_First)); + if constexpr (_Scan_reuse_output<_Ty, _FwdIt>) { + *_First = _Reduce_op(_Preceding, _STD move(*_First)); + } else { + *_First = _Reduce_op(_Preceding, _STD move(*_First2)); + ++_First2; + } } } @@ -4342,7 +4393,8 @@ struct _No_init_tag { }; // tag to indicate that no initial value is to be used template -_FwdIt2 _Exclusive_scan_per_chunk(_FwdIt1 _First, const _FwdIt1 _Last, _FwdIt2 _Dest, _BinOp _Reduce_op, _Ty& _Val) { +_FwdIt2 _Exclusive_scan_per_chunk(_FwdIt1 _First, const _FwdIt1 _Last, _FwdIt2 _Dest, _BinOp _Reduce_op, _Ty& _Val, + _Parallel_vector<_Ty>& _Intermediate_result) { // local-sum for parallel exclusive_scan; writes local sums into [_Dest + 1, _Dest + (_Last - _First)) and stores // successor sum in _Val // pre: _Val is *uninitialized* && _First != _Last @@ -4355,8 +4407,13 @@ _FwdIt2 _Exclusive_scan_per_chunk(_FwdIt1 _First, const _FwdIt1 _Last, _FwdIt2 _ } _Ty _Tmp = _Reduce_op(_Val, *_First); // temp to enable _First == _Dest - *_Dest = _Val; - _Val = _STD move(_Tmp); + if constexpr (_Scan_reuse_output<_Ty, _FwdIt2>) { + *_Dest = _Val; + } else { + _STL_INTERNAL_CHECK(_Intermediate_result.size() < _Intermediate_result.capacity()); + *_Dest = _Intermediate_result.emplace_back(_STD move(_Val)); + } + _Val = _STD move(_Tmp); } } @@ -4377,19 +4434,20 @@ void _Exclusive_scan_per_chunk_complete( } template -struct _Static_partitioned_exclusive_scan2 { +struct _Static_partitioned_exclusive_scan3 { using _Diff = _Common_diff_t<_FwdIt1, _FwdIt2>; _Static_partition_team<_Diff> _Team; _Static_partition_range<_FwdIt1, _Diff> _Basis1; _Static_partition_range<_FwdIt2, _Diff> _Basis2; _Parallel_vector<_Scan_decoupled_lookback<_Ty>> _Lookback; + _Scan_intermediate_storage<_Ty, _FwdIt2> _Intermediate_result; _Ty& _Initial; _BinOp _Reduce_op; - _Static_partitioned_exclusive_scan2(const size_t _Hw_threads, const _Diff _Count, const _FwdIt1 _First, + _Static_partitioned_exclusive_scan3(const size_t _Hw_threads, const _Diff _Count, const _FwdIt1 _First, _Ty& _Initial_, _BinOp _Reduce_op_, const _FwdIt2&) : _Team{_Count, _Get_chunked_work_chunk_count(_Hw_threads, _Count)}, _Basis1{}, _Basis2{}, - _Lookback(_Team._Chunks), _Initial(_Initial_), _Reduce_op(_Reduce_op_) { + _Lookback(_Team._Chunks), _Intermediate_result{_Team}, _Initial(_Initial_), _Reduce_op(_Reduce_op_) { _Basis1._Populate(_Team, _First); } @@ -4421,24 +4479,29 @@ struct _Static_partitioned_exclusive_scan2 { } // Calculate local sum and publish to other threads - const auto _Last = - _STD _Exclusive_scan_per_chunk(_In_range._First, _In_range._Last, _Dest, _Reduce_op, _Chunk->_Local._Ref()); + const auto _Last = _STD _Exclusive_scan_per_chunk(_In_range._First, _In_range._Last, _Dest, _Reduce_op, + _Chunk->_Local._Ref(), _Intermediate_result[_Chunk_number]); _Chunk->_Store_available_state(_Local_available); // Apply the predecessor overall sum to current overall sum and elements if (_Prev_chunk->_Get_available_state() & _Sum_available) { // predecessor overall sum done, use directly - _Chunk->_Apply_exclusive_predecessor(_Prev_chunk->_Sum._Ref(), _Dest, _Last, _Reduce_op); + _Chunk->_Apply_exclusive_predecessor( + _Prev_chunk->_Sum._Ref(), _Dest, _Intermediate_result[_Chunk_number].data(), _Last, _Reduce_op); } else { auto _Tmp = _STD _Get_lookback_sum(_Prev_chunk, _Reduce_op); - _Chunk->_Apply_exclusive_predecessor(_Tmp, _Dest, _Last, _Reduce_op); + _Chunk->_Apply_exclusive_predecessor( + _Tmp, _Dest, _Intermediate_result[_Chunk_number].data(), _Last, _Reduce_op); } + if constexpr (!_Scan_reuse_output<_Ty, _FwdIt2>) { + _Intermediate_result[_Chunk_number].clear(); + } return _Cancellation_status::_Running; } static void __stdcall _Threadpool_callback( __std_PTP_CALLBACK_INSTANCE, void* const _Context, __std_PTP_WORK) noexcept /* terminates */ { - _STD _Run_available_chunked_work(*static_cast<_Static_partitioned_exclusive_scan2*>(_Context)); + _STD _Run_available_chunked_work(*static_cast<_Static_partitioned_exclusive_scan3*>(_Context)); } }; @@ -4459,7 +4522,7 @@ _FwdIt2 exclusive_scan(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _Last, _FwdI const auto _UDest = _STD _Get_unwrapped_n(_Dest, _Count); if (_Count >= 2) { // ... with at least 2 elements _TRY_BEGIN - _Static_partitioned_exclusive_scan2 _Operation{ + _Static_partitioned_exclusive_scan3 _Operation{ _Hw_threads, _Count, _UFirst, _Val, _STD _Pass_fn(_Reduce_op), _UDest}; _STD _Seek_wrapped(_Dest, _Operation._Basis2._Populate(_Operation._Team, _UDest)); // Note that _Val is used as temporary storage by whichever thread runs the first chunk. @@ -4484,9 +4547,9 @@ _FwdIt2 exclusive_scan(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _Last, _FwdI return _Dest; } -template -_FwdIt2 _Inclusive_scan_per_chunk( - _FwdIt1 _First, const _FwdIt1 _Last, _FwdIt2 _Dest, _BinOp _Reduce_op, _Ty& _Val, _Ty_fwd&& _Predecessor) { +template +_FwdIt2 _Inclusive_scan_per_chunk(_FwdIt1 _First, const _FwdIt1 _Last, _FwdIt2 _Dest, _BinOp _Reduce_op, _Ty& _Val, + _Ty_fwd&& _Predecessor, [[maybe_unused]] _VectorTy&... _Intermediate_result) { // local-sum for parallel inclusive_scan; writes local inclusive prefix sums into _Dest and stores overall sum in // _Val. // pre: _Val is *uninitialized* && _First != _Last @@ -4505,24 +4568,30 @@ _FwdIt2 _Inclusive_scan_per_chunk( return _Dest; } - _Val = _Reduce_op(_STD move(_Val), *_First); + if constexpr (sizeof...(_VectorTy) == 0 || _Scan_reuse_output<_Ty, _FwdIt2>) { + _Val = _Reduce_op(_STD move(_Val), *_First); + } else { + _STL_INTERNAL_CHECK(((_Intermediate_result.size() < _Intermediate_result.capacity()) && ...)); + _Val = _Reduce_op(_Intermediate_result.emplace_back(_STD move(_Val))..., *_First); + } } } template -struct _Static_partitioned_inclusive_scan2 { +struct _Static_partitioned_inclusive_scan3 { using _Diff = _Common_diff_t<_FwdIt1, _FwdIt2>; _Static_partition_team<_Diff> _Team; _Static_partition_range<_FwdIt1, _Diff> _Basis1; _Static_partition_range<_FwdIt2, _Diff> _Basis2; _Parallel_vector<_Scan_decoupled_lookback<_Ty>> _Lookback; + _Scan_intermediate_storage<_Ty, _FwdIt2> _Intermediate_result; _BinOp _Reduce_op; _Init_ty& _Initial; - _Static_partitioned_inclusive_scan2( + _Static_partitioned_inclusive_scan3( const size_t _Hw_threads, const _Diff _Count, _BinOp _Reduce_op_, _Init_ty& _Initial_) : _Team{_Count, _Get_chunked_work_chunk_count(_Hw_threads, _Count)}, _Basis1{}, _Basis2{}, - _Lookback(_Team._Chunks), _Reduce_op(_Reduce_op_), _Initial(_Initial_) {} + _Lookback(_Team._Chunks), _Intermediate_result{_Team}, _Reduce_op(_Reduce_op_), _Initial(_Initial_) {} _Cancellation_status _Process_chunk() { const auto _Key = _Team._Get_next_key(); @@ -4552,24 +4621,29 @@ struct _Static_partitioned_inclusive_scan2 { } // Calculate local sum and publish to other threads - const auto _Last = _STD _Inclusive_scan_per_chunk( - _In_range._First, _In_range._Last, _Dest, _Reduce_op, _Chunk->_Local._Ref(), _No_init_tag{}); + const auto _Last = _STD _Inclusive_scan_per_chunk(_In_range._First, _In_range._Last, _Dest, _Reduce_op, + _Chunk->_Local._Ref(), _No_init_tag{}, _Intermediate_result[_Chunk_number]); _Chunk->_Store_available_state(_Local_available); // Apply the predecessor overall sum to current overall sum and elements if (_Prev_chunk->_Get_available_state() & _Sum_available) { // predecessor overall sum done, use directly - _Chunk->_Apply_inclusive_predecessor(_Prev_chunk->_Sum._Ref(), _Dest, _Last, _Reduce_op); + _Chunk->_Apply_inclusive_predecessor( + _Prev_chunk->_Sum._Ref(), _Dest, _Intermediate_result[_Chunk_number].data(), _Last, _Reduce_op); } else { auto _Tmp = _STD _Get_lookback_sum(_Prev_chunk, _Reduce_op); - _Chunk->_Apply_inclusive_predecessor(_Tmp, _Dest, _Last, _Reduce_op); + _Chunk->_Apply_inclusive_predecessor( + _Tmp, _Dest, _Intermediate_result[_Chunk_number].data(), _Last, _Reduce_op); } + if constexpr (!_Scan_reuse_output<_Ty, _FwdIt2>) { + _Intermediate_result[_Chunk_number].clear(); + } return _Cancellation_status::_Running; } static void __stdcall _Threadpool_callback( __std_PTP_CALLBACK_INSTANCE, void* const _Context, __std_PTP_WORK) noexcept /* terminates */ { - _STD _Run_available_chunked_work(*static_cast<_Static_partitioned_inclusive_scan2*>(_Context)); + _STD _Run_available_chunked_work(*static_cast<_Static_partitioned_inclusive_scan3*>(_Context)); } }; @@ -4591,7 +4665,7 @@ _FwdIt2 inclusive_scan(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _B if (_Count >= 2) { // ... with at least 2 elements _TRY_BEGIN auto _Passed_op = _STD _Pass_fn(_Reduce_op); - _Static_partitioned_inclusive_scan2<_Ty, _Ty, _Unwrapped_t, decltype(_UDest), + _Static_partitioned_inclusive_scan3<_Ty, _Ty, _Unwrapped_t, decltype(_UDest), decltype(_Passed_op)> _Operation{_Hw_threads, _Count, _Passed_op, _Val}; _Operation._Basis1._Populate(_Operation._Team, _UFirst); @@ -4637,7 +4711,7 @@ _FwdIt2 inclusive_scan(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _B _TRY_BEGIN _No_init_tag _Tag; auto _Passed_op = _STD _Pass_fn(_Reduce_op); - _Static_partitioned_inclusive_scan2<_Iter_value_t<_FwdIt1>, _No_init_tag, _Unwrapped_t, + _Static_partitioned_inclusive_scan3<_Iter_value_t<_FwdIt1>, _No_init_tag, _Unwrapped_t, decltype(_UDest), decltype(_Passed_op)> _Operation{_Hw_threads, _Count, _Passed_op, _Tag}; _Operation._Basis1._Populate(_Operation._Team, _UFirst); @@ -4661,8 +4735,8 @@ _FwdIt2 inclusive_scan(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _B } template -_FwdIt2 _Transform_exclusive_scan_per_chunk( - _FwdIt1 _First, const _FwdIt1 _Last, _FwdIt2 _Dest, _BinOp _Reduce_op, _UnaryOp _Transform_op, _Ty& _Val) { +_FwdIt2 _Transform_exclusive_scan_per_chunk(_FwdIt1 _First, const _FwdIt1 _Last, _FwdIt2 _Dest, _BinOp _Reduce_op, + _UnaryOp _Transform_op, _Ty& _Val, _Parallel_vector<_Ty>& _Intermediate_result) { // Local-sum for parallel transform_exclusive_scan; writes local sums into [_Dest + 1, _Dest + (_Last - _First)) and // stores successor sum in _Val. // pre: _Val is *uninitialized* && _First != _Last @@ -4675,8 +4749,13 @@ _FwdIt2 _Transform_exclusive_scan_per_chunk( } _Ty _Tmp = _Reduce_op(_Val, _Transform_op(*_First)); // temp to enable _First == _Dest - *_Dest = _Val; - _Val = _STD move(_Tmp); + if constexpr (_Scan_reuse_output<_Ty, _FwdIt2>) { + *_Dest = _Val; + } else { + _STL_INTERNAL_CHECK(_Intermediate_result.size() < _Intermediate_result.capacity()); + *_Dest = _Intermediate_result.emplace_back(_STD move(_Val)); + } + _Val = _STD move(_Tmp); } } @@ -4698,20 +4777,22 @@ void _Transform_exclusive_scan_per_chunk_complete(_FwdIt1 _First, const _FwdIt1 } template -struct _Static_partitioned_transform_exclusive_scan2 { +struct _Static_partitioned_transform_exclusive_scan3 { using _Diff = _Common_diff_t<_FwdIt1, _FwdIt2>; _Static_partition_team<_Diff> _Team; _Static_partition_range<_FwdIt1, _Diff> _Basis1; _Static_partition_range<_FwdIt2, _Diff> _Basis2; _Parallel_vector<_Scan_decoupled_lookback<_Ty>> _Lookback; + _Scan_intermediate_storage<_Ty, _FwdIt2> _Intermediate_result; _Ty& _Initial; _BinOp _Reduce_op; _UnaryOp _Transform_op; - _Static_partitioned_transform_exclusive_scan2(const size_t _Hw_threads, const _Diff _Count, const _FwdIt1 _First, + _Static_partitioned_transform_exclusive_scan3(const size_t _Hw_threads, const _Diff _Count, const _FwdIt1 _First, _Ty& _Initial_, _BinOp _Reduce_op_, _UnaryOp _Transform_op_, const _FwdIt2&) : _Team{_Count, _Get_chunked_work_chunk_count(_Hw_threads, _Count)}, _Basis1{}, _Basis2{}, - _Lookback(_Team._Chunks), _Initial(_Initial_), _Reduce_op(_Reduce_op_), _Transform_op(_Transform_op_) { + _Lookback(_Team._Chunks), _Intermediate_result{_Team}, _Initial(_Initial_), _Reduce_op(_Reduce_op_), + _Transform_op(_Transform_op_) { _Basis1._Populate(_Team, _First); } @@ -4743,24 +4824,29 @@ struct _Static_partitioned_transform_exclusive_scan2 { } // Calculate local sum and publish to other threads - const auto _Last = _STD _Transform_exclusive_scan_per_chunk( - _In_range._First, _In_range._Last, _Dest, _Reduce_op, _Transform_op, _Chunk->_Local._Ref()); + const auto _Last = _STD _Transform_exclusive_scan_per_chunk(_In_range._First, _In_range._Last, _Dest, + _Reduce_op, _Transform_op, _Chunk->_Local._Ref(), _Intermediate_result[_Chunk_number]); _Chunk->_Store_available_state(_Local_available); // Apply the predecessor overall sum to current overall sum and elements if (_Prev_chunk->_Get_available_state() & _Sum_available) { // predecessor overall sum done, use directly - _Chunk->_Apply_exclusive_predecessor(_Prev_chunk->_Sum._Ref(), _Dest, _Last, _Reduce_op); + _Chunk->_Apply_exclusive_predecessor( + _Prev_chunk->_Sum._Ref(), _Dest, _Intermediate_result[_Chunk_number].data(), _Last, _Reduce_op); } else { auto _Tmp = _STD _Get_lookback_sum(_Prev_chunk, _Reduce_op); - _Chunk->_Apply_exclusive_predecessor(_Tmp, _Dest, _Last, _Reduce_op); + _Chunk->_Apply_exclusive_predecessor( + _Tmp, _Dest, _Intermediate_result[_Chunk_number].data(), _Last, _Reduce_op); } + if constexpr (!_Scan_reuse_output<_Ty, _FwdIt2>) { + _Intermediate_result[_Chunk_number].clear(); + } return _Cancellation_status::_Running; } static void __stdcall _Threadpool_callback( __std_PTP_CALLBACK_INSTANCE, void* const _Context, __std_PTP_WORK) noexcept /* terminates */ { - _STD _Run_available_chunked_work(*static_cast<_Static_partitioned_transform_exclusive_scan2*>(_Context)); + _STD _Run_available_chunked_work(*static_cast<_Static_partitioned_transform_exclusive_scan3*>(_Context)); } }; @@ -4781,7 +4867,7 @@ _FwdIt2 transform_exclusive_scan(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _L const auto _UDest = _STD _Get_unwrapped_n(_Dest, _Count); if (_Count >= 2) { // ... with at least 2 elements _TRY_BEGIN - _Static_partitioned_transform_exclusive_scan2 _Operation{_Hw_threads, _Count, _UFirst, _Val, + _Static_partitioned_transform_exclusive_scan3 _Operation{_Hw_threads, _Count, _UFirst, _Val, _STD _Pass_fn(_Reduce_op), _STD _Pass_fn(_Transform_op), _UDest}; _STD _Seek_wrapped(_Dest, _Operation._Basis2._Populate(_Operation._Team, _UDest)); // Note that _Val is used as temporary storage by whichever thread runs the first chunk. @@ -4806,9 +4892,9 @@ _FwdIt2 transform_exclusive_scan(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _L return _Dest; } -template +template _FwdIt2 _Transform_inclusive_scan_per_chunk(_FwdIt1 _First, const _FwdIt1 _Last, _FwdIt2 _Dest, _BinOp _Reduce_op, - _UnaryOp _Transform_op, _Ty& _Val, _Ty_fwd&& _Predecessor) { + _UnaryOp _Transform_op, _Ty& _Val, _Ty_fwd&& _Predecessor, [[maybe_unused]] _VectorTy&... _Intermediate_result) { // local-sum for parallel transform_inclusive_scan; writes local inclusive prefix sums into _Dest and stores overall // sum in _Val // pre: _Val is *uninitialized* && _First != _Last @@ -4827,25 +4913,32 @@ _FwdIt2 _Transform_inclusive_scan_per_chunk(_FwdIt1 _First, const _FwdIt1 _Last, return _Dest; } - _Val = _Reduce_op(_STD move(_Val), _Transform_op(*_First)); + if constexpr (sizeof...(_VectorTy) == 0 || _Scan_reuse_output<_Ty, _FwdIt2>) { + _Val = _Reduce_op(_STD move(_Val), _Transform_op(*_First)); + } else { + _STL_INTERNAL_CHECK(((_Intermediate_result.size() < _Intermediate_result.capacity()) && ...)); + _Val = _Reduce_op(_Intermediate_result.emplace_back(_STD move(_Val))..., _Transform_op(*_First)); + } } } template -struct _Static_partitioned_transform_inclusive_scan2 { +struct _Static_partitioned_transform_inclusive_scan3 { using _Diff = _Common_diff_t<_FwdIt1, _FwdIt2>; _Static_partition_team<_Diff> _Team; _Static_partition_range<_FwdIt1, _Diff> _Basis1; _Static_partition_range<_FwdIt2, _Diff> _Basis2; _Parallel_vector<_Scan_decoupled_lookback<_Ty>> _Lookback; + _Scan_intermediate_storage<_Ty, _FwdIt2> _Intermediate_result; _BinOp _Reduce_op; _UnaryOp _Transform_op; _Init_ty& _Initial; - _Static_partitioned_transform_inclusive_scan2( + _Static_partitioned_transform_inclusive_scan3( const size_t _Hw_threads, const _Diff _Count, _BinOp _Reduce_op_, _UnaryOp _Transform_op_, _Init_ty& _Initial_) : _Team{_Count, _Get_chunked_work_chunk_count(_Hw_threads, _Count)}, _Basis1{}, _Basis2{}, - _Lookback(_Team._Chunks), _Reduce_op(_Reduce_op_), _Transform_op(_Transform_op_), _Initial(_Initial_) {} + _Lookback(_Team._Chunks), _Intermediate_result{_Team}, _Reduce_op(_Reduce_op_), _Transform_op(_Transform_op_), + _Initial(_Initial_) {} _Cancellation_status _Process_chunk() { const auto _Key = _Team._Get_next_key(); @@ -4875,24 +4968,29 @@ struct _Static_partitioned_transform_inclusive_scan2 { } // Calculate local sum and publish to other threads - const auto _Last = _STD _Transform_inclusive_scan_per_chunk( - _In_range._First, _In_range._Last, _Dest, _Reduce_op, _Transform_op, _Chunk->_Local._Ref(), _No_init_tag{}); + const auto _Last = _STD _Transform_inclusive_scan_per_chunk(_In_range._First, _In_range._Last, _Dest, + _Reduce_op, _Transform_op, _Chunk->_Local._Ref(), _No_init_tag{}, _Intermediate_result[_Chunk_number]); _Chunk->_Store_available_state(_Local_available); // Apply the predecessor overall sum to current overall sum and elements if (_Prev_chunk->_Get_available_state() & _Sum_available) { // predecessor overall sum done, use directly - _Chunk->_Apply_inclusive_predecessor(_Prev_chunk->_Sum._Ref(), _Dest, _Last, _Reduce_op); + _Chunk->_Apply_inclusive_predecessor( + _Prev_chunk->_Sum._Ref(), _Dest, _Intermediate_result[_Chunk_number].data(), _Last, _Reduce_op); } else { auto _Tmp = _STD _Get_lookback_sum(_Prev_chunk, _Reduce_op); - _Chunk->_Apply_inclusive_predecessor(_Tmp, _Dest, _Last, _Reduce_op); + _Chunk->_Apply_inclusive_predecessor( + _Tmp, _Dest, _Intermediate_result[_Chunk_number].data(), _Last, _Reduce_op); } + if constexpr (!_Scan_reuse_output<_Ty, _FwdIt2>) { + _Intermediate_result[_Chunk_number].clear(); + } return _Cancellation_status::_Running; } static void __stdcall _Threadpool_callback( __std_PTP_CALLBACK_INSTANCE, void* const _Context, __std_PTP_WORK) noexcept /* terminates */ { - _STD _Run_available_chunked_work(*static_cast<_Static_partitioned_transform_inclusive_scan2*>(_Context)); + _STD _Run_available_chunked_work(*static_cast<_Static_partitioned_transform_inclusive_scan3*>(_Context)); } }; @@ -4915,7 +5013,7 @@ _FwdIt2 transform_inclusive_scan(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _L _TRY_BEGIN auto _Passed_reduce = _STD _Pass_fn(_Reduce_op); auto _Passed_transform = _STD _Pass_fn(_Transform_op); - _Static_partitioned_transform_inclusive_scan2<_Ty, _Ty, _Unwrapped_t, decltype(_UDest), + _Static_partitioned_transform_inclusive_scan3<_Ty, _Ty, _Unwrapped_t, decltype(_UDest), decltype(_Passed_reduce), decltype(_Passed_transform)> _Operation{_Hw_threads, _Count, _Passed_reduce, _Passed_transform, _Val}; _Operation._Basis1._Populate(_Operation._Team, _UFirst); @@ -4963,7 +5061,7 @@ _FwdIt2 transform_inclusive_scan(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _L auto _Passed_reduce = _STD _Pass_fn(_Reduce_op); auto _Passed_transform = _STD _Pass_fn(_Transform_op); using _Intermediate_t = decay_t; - _Static_partitioned_transform_inclusive_scan2<_Intermediate_t, _No_init_tag, + _Static_partitioned_transform_inclusive_scan3<_Intermediate_t, _No_init_tag, _Unwrapped_t, decltype(_UDest), decltype(_Passed_reduce), decltype(_Passed_transform)> _Operation{_Hw_threads, _Count, _Passed_reduce, _Passed_transform, _Tag}; diff --git a/stl/inc/expected b/stl/inc/expected index aad81b7007e..fd82ba69ac1 100644 --- a/stl/inc/expected +++ b/stl/inc/expected @@ -258,6 +258,8 @@ public: is_trivially_copy_constructible_v<_Ty> && is_trivially_copy_constructible_v<_Err> = default; // clang-format on + expected(const expected&) = delete; + constexpr expected(expected&& _Other) noexcept( is_nothrow_move_constructible_v<_Ty> && is_nothrow_move_constructible_v<_Err>) requires (!(is_trivially_move_constructible_v<_Ty> && is_trivially_move_constructible_v<_Err>) @@ -441,6 +443,8 @@ public: && _Trivially_copy_constructible_assignable_destructible<_Err> = default; + expected& operator=(const expected&) = delete; + constexpr expected& operator=(expected&& _Other) noexcept( is_nothrow_move_constructible_v<_Ty> && is_nothrow_move_constructible_v<_Err> && is_nothrow_move_assignable_v<_Ty> && is_nothrow_move_assignable_v<_Err>) @@ -1243,6 +1247,8 @@ public: expected(const expected&) requires is_trivially_copy_constructible_v<_Err> = default; // clang-format on + expected(const expected&) = delete; + constexpr expected(expected&& _Other) noexcept(is_nothrow_move_constructible_v<_Err>) requires (!is_trivially_move_constructible_v<_Err> && is_move_constructible_v<_Err>) : _Has_value(_Other._Has_value) { @@ -1344,6 +1350,8 @@ public: requires _Expected_unary_copy_assignable<_Err> && _Trivially_copy_constructible_assignable_destructible<_Err> = default; + expected& operator=(const expected&) = delete; + constexpr expected& operator=(expected&& _Other) noexcept( is_nothrow_move_constructible_v<_Err> && is_nothrow_move_assignable_v<_Err>) requires _Expected_unary_move_assignable<_Err> diff --git a/stl/inc/format b/stl/inc/format index be7a99523d6..c2af86f05a3 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -4774,6 +4774,38 @@ public: private: _Fill_align_and_width_specs<_CharT> _Specs; }; + +// Per LWG-3997, `_CharT` in library-provided `formatter` specializations is +// constrained to character types supported by `format`. +template class _RefView> +struct _Adaptor_formatter_base { +private: + using _Container = _AdaptorType::container_type; + using _Maybe_const_container = _Fmt_maybe_const<_Container, _CharT>; + using _Maybe_const_adaptor = _Maybe_const, _AdaptorType>; + + formatter<_RefView<_Maybe_const_container>, _CharT> _Underlying; + +public: + template + constexpr _ParseCtx::iterator parse(_ParseCtx& _Ctx) { + return _Underlying.parse(_Ctx); + } + + template + _FmtCtx::iterator format(_Maybe_const_adaptor& _Adaptor, _FmtCtx& _Ctx) const { + struct _Container_exposer : _AdaptorType { + using _AdaptorType::c; + + _Container_exposer(const _Container_exposer&) = delete; + _Container_exposer& operator=(const _Container_exposer&) = delete; + ~_Container_exposer() = delete; + }; + + constexpr auto _Mem_cont_ptr = &_Container_exposer::c; + return _Underlying.format(_Adaptor.*_Mem_cont_ptr, _Ctx); + } +}; #endif // _HAS_CXX23 _STD_END diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 2535e0d5cd3..ce21eb7428d 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -81,7 +81,7 @@ private: rank_type _Counter = 0; for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) { if (_Static_extents[_Idx] == dynamic_extent) { - _Analysis_assume_(_Counter < _Rank_dynamic); // TRANSITION, DevCom-923103 + _Analysis_assume_(_Counter < _Rank_dynamic); // guaranteed by how _Rank_dynamic is calculated _Result[_Counter] = _Idx; ++_Counter; } @@ -174,7 +174,7 @@ private: } public: - _NODISCARD static constexpr rank_type rank() noexcept { + _NODISCARD _Ret_range_(==, _Rank) static constexpr rank_type rank() noexcept { return _Rank; } @@ -182,14 +182,14 @@ public: return _Rank_dynamic; } - _NODISCARD static constexpr size_t static_extent(const rank_type _Idx) noexcept { + _NODISCARD static constexpr size_t static_extent(_In_range_(<, _Rank) const rank_type _Idx) noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Idx < _Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/1)"); #endif // _CONTAINER_DEBUG_LEVEL > 0 return _Static_extents[_Idx]; } - _NODISCARD constexpr index_type extent(const rank_type _Idx) const noexcept { + _NODISCARD constexpr index_type extent(_In_range_(<, _Rank) const rank_type _Idx) const noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Idx < _Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/3)"); #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -591,7 +591,7 @@ public: return true; } - _NODISCARD constexpr index_type stride(const rank_type _Idx) const noexcept + _NODISCARD constexpr index_type stride(_In_range_(<, extents_type::_Rank) const rank_type _Idx) const noexcept requires (extents_type::rank() > 0) { #if _CONTAINER_DEBUG_LEVEL > 0 @@ -744,7 +744,7 @@ public: return true; } - _NODISCARD constexpr index_type stride(const rank_type _Idx) const noexcept + _NODISCARD constexpr index_type stride(_In_range_(<, extents_type::_Rank) const rank_type _Idx) const noexcept requires (extents_type::rank() > 0) { #if _CONTAINER_DEBUG_LEVEL > 0 @@ -975,10 +975,14 @@ public: return true; } - _NODISCARD constexpr index_type stride(const rank_type _Idx) const noexcept { + _NODISCARD constexpr index_type stride(_In_range_(<, extents_type::_Rank) const rank_type _Idx) const noexcept { if constexpr (extents_type::rank() == 0) { _STL_VERIFY(false, "The argument to stride must be nonnegative and less than extents_type::rank()."); } else { +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(_Idx < extents_type::_Rank, + "The argument to stride must be nonnegative and less than extents_type::rank()."); +#endif // _CONTAINER_DEBUG_LEVEL > 0 return this->_Array[_Idx]; } } @@ -1187,7 +1191,7 @@ private: "[mdspan.mdspan.overview]/2.3)."); public: - _NODISCARD static constexpr rank_type rank() noexcept { + _NODISCARD _Ret_range_(==, extents_type::_Rank) static constexpr rank_type rank() noexcept { return extents_type::_Rank; } @@ -1195,14 +1199,14 @@ public: return extents_type::_Rank_dynamic; } - _NODISCARD static constexpr size_t static_extent(const rank_type _Idx) noexcept { + _NODISCARD static constexpr size_t static_extent(_In_range_(<, extents_type::_Rank) const rank_type _Idx) noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Idx < extents_type::_Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/1)"); #endif // _CONTAINER_DEBUG_LEVEL > 0 return extents_type::_Static_extents[_Idx]; } - _NODISCARD constexpr index_type extent(const rank_type _Idx) const noexcept { + _NODISCARD constexpr index_type extent(_In_range_(<, extents_type::_Rank) const rank_type _Idx) const noexcept { return this->_Map.extents().extent(_Idx); } diff --git a/stl/inc/mutex b/stl/inc/mutex index 3bf8b71ce60..0daa8314b5b 100644 --- a/stl/inc/mutex +++ b/stl/inc/mutex @@ -599,7 +599,7 @@ public: const unsigned long _Rel_ms_count = _Clamped_rel_time_ms_count(_Abs_time - _Now)._Count; - const _Thrd_result _Res = _Cnd_timedwait_for(_Mycnd(), _Lck.mutex()->_Mymtx(), _Rel_ms_count); + const _Thrd_result _Res = _Cnd_timedwait_for_unchecked(_Mycnd(), _Lck.mutex()->_Mymtx(), _Rel_ms_count); if (_Res == _Thrd_result::_Success) { return cv_status::no_timeout; } diff --git a/stl/inc/queue b/stl/inc/queue index b61ce25002d..832ed8fbc33 100644 --- a/stl/inc/queue +++ b/stl/inc/queue @@ -18,6 +18,7 @@ #if _HAS_CXX23 #include <__msvc_ranges_to.hpp> +#include #include #endif // _HAS_CXX23 @@ -223,6 +224,14 @@ void swap(queue<_Ty, _Container>& _Left, queue<_Ty, _Container>& _Right) noexcep template struct uses_allocator, _Alloc> : uses_allocator<_Container, _Alloc>::type {}; +#if _HAS_CXX23 +// Per LWG-3997, `_CharT` in library-provided `formatter` specializations is +// constrained to character types supported by `format`. +template <_Format_supported_charT _CharT, class _Ty, formattable<_CharT> _Container> +struct formatter, _CharT> + : _Adaptor_formatter_base, _CharT, _RANGES ref_view> {}; +#endif // _HAS_CXX23 + _EXPORT_STD template , class _Pr = less> class priority_queue { public: @@ -490,6 +499,13 @@ void swap(priority_queue<_Ty, _Container, _Pr>& _Left, priority_queue<_Ty, _Cont template struct uses_allocator, _Alloc> : uses_allocator<_Container, _Alloc>::type {}; +#if _HAS_CXX23 +// Per LWG-3997, `_CharT` in library-provided `formatter` specializations is +// constrained to character types supported by `format`. +template <_Format_supported_charT _CharT, class _Ty, formattable<_CharT> _Container, class _Comp> +struct formatter, _CharT> + : _Adaptor_formatter_base, _CharT, _RANGES ref_view> {}; +#endif // _HAS_CXX23 _STD_END #pragma pop_macro("new") diff --git a/stl/inc/random b/stl/inc/random index a429b7ab954..d943cd1305c 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -310,32 +310,32 @@ _NODISCARD _Real generate_canonical(_Gen& _Gx) { // build a floating-point value constexpr auto _Gxmax = (_Gen::max)(); constexpr auto _Params = _Generate_canonical_params(_Minbits, _Gxmax - _Gxmin); - using _Sx_type = conditional_t<_Params._Smax_bits <= 32, uint32_t, - conditional_t<_Params._Smax_bits <= 64, uint64_t, _Unsigned128>>; - _Sx_type _Sx; + _STL_INTERNAL_STATIC_ASSERT(_Params._Kx >= 1); if constexpr (_Params._Rx_is_pow2) { - // Always needs only one attempt. Multiplications can be replaced with shift/add. Optimize k=1 case. - if constexpr (_Params._Kx == 1) { - _Sx = static_cast<_Sx_type>(_Gx() - _Gxmin); - } else if constexpr (_Params._Kx > 1) { + // Always needs only one attempt. Multiplications can be replaced with shift/add. + constexpr int _Discarded_bits = _Params._Smax_bits - _Minbits; + _Result_uint_type _Sx = static_cast<_Result_uint_type>((_Gx() - _Gxmin) >> _Discarded_bits); + + if constexpr (_Params._Kx > 1) { constexpr int _Rx_bits = _Params._Smax_bits / _Params._Kx; - _Sx = 0; - int _Shift = 0; - for (int _Idx = 0; _Idx < _Params._Kx; ++_Idx) { - _Sx += static_cast<_Sx_type>(_Gx() - _Gxmin) << _Shift; + int _Shift = -_Discarded_bits; + for (int _Idx = 1; _Idx < _Params._Kx; ++_Idx) { _Shift += _Rx_bits; + _Sx += static_cast<_Result_uint_type>(_Gx() - _Gxmin) << _Shift; } - } else { - _STL_INTERNAL_STATIC_ASSERT(false); // unexpected k } - _Sx >>= _Params._Smax_bits - _Minbits; - return static_cast<_Real>(static_cast<_Result_uint_type>(_Sx)) * static_cast<_Real>(_Params._Scale); + return static_cast<_Real>(_Sx) * static_cast<_Real>(_Params._Scale); } else { + using _Sx_type = conditional_t<_Params._Smax_bits <= 32, uint32_t, + conditional_t<_Params._Smax_bits <= 64, uint64_t, _Unsigned128>>; + constexpr auto _Rx = _Sx_type{_Gxmax - _Gxmin} + 1u; constexpr _Sx_type _Limit = static_cast<_Sx_type>(_Params._Xx) * (_Sx_type{1} << _Minbits); + _Sx_type _Sx; + do { // unroll first two iterations to avoid unnecessary multiplications _Sx = static_cast<_Sx_type>(_Gx() - _Gxmin); diff --git a/stl/inc/stack b/stl/inc/stack index e98e69dee43..09931202339 100644 --- a/stl/inc/stack +++ b/stl/inc/stack @@ -11,6 +11,7 @@ #if _HAS_CXX23 #include <__msvc_ranges_to.hpp> +#include #include #endif // _HAS_CXX23 @@ -209,6 +210,14 @@ void swap(stack<_Ty, _Container>& _Left, stack<_Ty, _Container>& _Right) noexcep template struct uses_allocator, _Alloc> : uses_allocator<_Container, _Alloc>::type {}; + +#if _HAS_CXX23 +// Per LWG-3997, `_CharT` in library-provided `formatter` specializations is +// constrained to character types supported by `format`. +template <_Format_supported_charT _CharT, class _Ty, formattable<_CharT> _Container> +struct formatter, _CharT> + : _Adaptor_formatter_base, _CharT, _RANGES ref_view> {}; +#endif // _HAS_CXX23 _STD_END #pragma pop_macro("new") diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 48f056d3c22..3f941094cd8 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -37,14 +37,14 @@ struct _Conjunction { // handle false trait or last trait template struct _Conjunction { // the first trait is true, try the next one - using type = typename _Conjunction<_Next::value, _Next, _Rest...>::type; + using type = typename _Conjunction(_Next::value), _Next, _Rest...>::type; }; _EXPORT_STD template struct conjunction : true_type {}; // If _Traits is empty, true_type template -struct conjunction<_First, _Rest...> : _Conjunction<_First::value, _First, _Rest...>::type { +struct conjunction<_First, _Rest...> : _Conjunction(_First::value), _First, _Rest...>::type { // the first false trait in _Traits, or the last trait if none are false }; @@ -1295,23 +1295,14 @@ template using _Conditional_type = decltype(false ? _STD declval<_Ty1>() : _STD declval<_Ty2>()); #if _HAS_CXX20 -#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10648215 template -#else // ^^^ no workaround / workaround vvv -template -#endif // ^^^ workaround ^^^ -struct _Const_lvalue_cond_oper { -}; +struct _Const_lvalue_cond_oper {}; // N4950 [meta.trans.other]/3.3.4 (per the proposed resolution of LWG-3205): "Otherwise, if remove_cvref_t denotes // a type..." template -#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10648215 requires requires { typename _Conditional_type; } struct _Const_lvalue_cond_oper<_Ty1, _Ty2> { -#else // ^^^ no workaround / workaround vvv -struct _Const_lvalue_cond_oper<_Ty1, _Ty2, void_t<_Conditional_type>> { -#endif // ^^^ workaround ^^^ using type = remove_cvref_t<_Conditional_type>; }; diff --git a/stl/inc/utility b/stl/inc/utility index df825320fd6..f86e318e398 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -30,9 +30,11 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("msvc") #pragma push_macro("intrinsic") #pragma push_macro("known_semantics") +#pragma push_macro("lifetimebound") #undef msvc #undef intrinsic #undef known_semantics +#undef lifetimebound _STD_BEGIN _EXPORT_STD template @@ -59,8 +61,8 @@ _EXPORT_STD template using index_sequence_for = make_index_sequence; _EXPORT_STD template -_NODISCARD constexpr const _Ty&(max) (const _Ty& _Left, const _Ty& _Right, _Pr _Pred) noexcept( - noexcept(_Pred(_Left, _Right))) /* strengthened */ { +_NODISCARD constexpr const _Ty&(max) (const _Ty& _Left _MSVC_LIFETIMEBOUND, const _Ty& _Right _MSVC_LIFETIMEBOUND, + _Pr _Pred) noexcept(noexcept(_Pred(_Left, _Right))) /* strengthened */ { // return larger of _Left and _Right return _Pred(_Left, _Right) ? _Right : _Left; } @@ -69,7 +71,8 @@ _NODISCARD constexpr const _Ty&(max) (const _Ty& _Left, const _Ty& _Right, _Pr _ #pragma warning(disable : 28285) // (syntax error in SAL annotation, occurs when _Ty is not an integral type) _EXPORT_STD template _NODISCARD _Post_equal_to_(_Left < _Right ? _Right : _Left) constexpr const _Ty& // - (max) (const _Ty& _Left, const _Ty& _Right) noexcept(noexcept(_Left < _Right)) /* strengthened */ { + (max) (const _Ty& _Left _MSVC_LIFETIMEBOUND, const _Ty& _Right _MSVC_LIFETIMEBOUND) noexcept( + noexcept(_Left < _Right)) /* strengthened */ { // return larger of _Left and _Right return _Left < _Right ? _Right : _Left; } @@ -82,8 +85,8 @@ _EXPORT_STD template _NODISCARD constexpr _Ty(max)(initializer_list<_Ty>); // implemented in _EXPORT_STD template -_NODISCARD constexpr const _Ty&(min) (const _Ty& _Left, const _Ty& _Right, _Pr _Pred) noexcept( - noexcept(_Pred(_Right, _Left))) /* strengthened */ { +_NODISCARD constexpr const _Ty&(min) (const _Ty& _Left _MSVC_LIFETIMEBOUND, const _Ty& _Right _MSVC_LIFETIMEBOUND, + _Pr _Pred) noexcept(noexcept(_Pred(_Right, _Left))) /* strengthened */ { // return smaller of _Left and _Right return _Pred(_Right, _Left) ? _Right : _Left; } @@ -92,7 +95,8 @@ _NODISCARD constexpr const _Ty&(min) (const _Ty& _Left, const _Ty& _Right, _Pr _ #pragma warning(disable : 28285) // (syntax error in SAL annotation, occurs when _Ty is not an integral type) _EXPORT_STD template _NODISCARD _Post_equal_to_(_Right < _Left ? _Right : _Left) constexpr const _Ty& // - (min) (const _Ty& _Left, const _Ty& _Right) noexcept(noexcept(_Right < _Left)) /* strengthened */ { + (min) (const _Ty& _Left _MSVC_LIFETIMEBOUND, const _Ty& _Right _MSVC_LIFETIMEBOUND) noexcept( + noexcept(_Right < _Left)) /* strengthened */ { // return smaller of _Left and _Right return _Right < _Left ? _Right : _Left; } @@ -969,6 +973,7 @@ namespace _DEPRECATE_TR1_NAMESPACE tr1 { _STD_END // TRANSITION, non-_Ugly attribute tokens +#pragma pop_macro("lifetimebound") #pragma pop_macro("known_semantics") #pragma pop_macro("intrinsic") #pragma pop_macro("msvc") diff --git a/stl/inc/vector b/stl/inc/vector index bc99da1dc7b..141068db916 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -788,7 +788,7 @@ private: if constexpr (conjunction_v, _Uses_default_construct<_Alloc, _Ty*, _Valty...>>) { _ASAN_VECTOR_MODIFY(1); - _Construct_in_place(*_Mylast, _STD forward<_Valty>(_Val)...); + _STD _Construct_in_place(*_Mylast, _STD forward<_Valty>(_Val)...); } else { _ASAN_VECTOR_EXTEND_GUARD(static_cast(_Mylast - _My_data._Myfirst) + 1); _Alty_traits::construct(_Getal(), _Unfancy(_Mylast), _STD forward<_Valty>(_Val)...); @@ -822,27 +822,27 @@ private: const size_type _Newsize = _Oldsize + 1; size_type _Newcapacity = _Calculate_growth(_Newsize); - const pointer _Newvec = _Allocate_at_least_helper(_Al, _Newcapacity); + const pointer _Newvec = _STD _Allocate_at_least_helper(_Al, _Newcapacity); const pointer _Constructed_last = _Newvec + _Whereoff + 1; pointer _Constructed_first = _Constructed_last; _TRY_BEGIN - _Alty_traits::construct(_Al, _Unfancy(_Newvec + _Whereoff), _STD forward<_Valty>(_Val)...); + _Alty_traits::construct(_Al, _STD _Unfancy(_Newvec + _Whereoff), _STD forward<_Valty>(_Val)...); _Constructed_first = _Newvec + _Whereoff; if (_Whereptr == _Mylast) { // at back, provide strong guarantee if constexpr (is_nothrow_move_constructible_v<_Ty> || !is_copy_constructible_v<_Ty>) { - _Uninitialized_move(_Myfirst, _Mylast, _Newvec, _Al); + _STD _Uninitialized_move(_Myfirst, _Mylast, _Newvec, _Al); } else { - _Uninitialized_copy(_Myfirst, _Mylast, _Newvec, _Al); + _STD _Uninitialized_copy(_Myfirst, _Mylast, _Newvec, _Al); } } else { // provide basic guarantee - _Uninitialized_move(_Myfirst, _Whereptr, _Newvec, _Al); + _STD _Uninitialized_move(_Myfirst, _Whereptr, _Newvec, _Al); _Constructed_first = _Newvec; - _Uninitialized_move(_Whereptr, _Mylast, _Newvec + _Whereoff + 1, _Al); + _STD _Uninitialized_move(_Whereptr, _Mylast, _Newvec + _Whereoff + 1, _Al); } _CATCH_ALL - _Destroy_range(_Constructed_first, _Constructed_last, _Al); + _STD _Destroy_range(_Constructed_first, _Constructed_last, _Al); _Al.deallocate(_Newvec, _Newcapacity); _RERAISE; _CATCH_END @@ -1707,9 +1707,9 @@ public: auto& _My_data = _Mypair._Myval2; pointer& _Mylast = _My_data._Mylast; -#if _ITERATOR_DEBUG_LEVEL == 2 +#if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_My_data._Myfirst != _Mylast, "vector empty before pop"); -#endif // _ITERATOR_DEBUG_LEVEL == 2 +#endif // _CONTAINER_DEBUG_LEVEL > 0 _Orphan_range(_Mylast - 1, _Mylast); _Alty_traits::destroy(_Getal(), _Unfancy(_Mylast - 1)); @@ -2024,7 +2024,7 @@ private: _My_data._Orphan_all(); if (_Myfirst) { // destroy and deallocate old array - _Destroy_range(_Myfirst, _Mylast, _Al); + _STD _Destroy_range(_Myfirst, _Mylast, _Al); _ASAN_VECTOR_REMOVE; _Al.deallocate(_Myfirst, static_cast(_Myend - _Myfirst)); } diff --git a/stl/inc/xatomic.h b/stl/inc/xatomic.h index daf370b761b..156cf525c4c 100644 --- a/stl/inc/xatomic.h +++ b/stl/inc/xatomic.h @@ -58,6 +58,11 @@ _STL_DISABLE_CLANG_WARNINGS #if defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_HYBRID_X86_ARM64) #define _Memory_barrier() __dmb(0xB) // inner shared data memory barrier #define _Compiler_or_memory_barrier() _Memory_barrier() +#if defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_HYBRID_X86_ARM64) +#define _Memory_load_acquire_barrier() __dmb(0x9) // inner shared data memory load barrier +#else // ^^^ ARM64/ARM64EC/HYBRID_X86_ARM64 / ARM32 vvv +#define _Memory_load_acquire_barrier() _Memory_barrier() +#endif // ^^^ ARM32 ^^^ #elif defined(_M_IX86) || defined(_M_X64) // x86/x64 hardware only emits memory barriers inside _Interlocked intrinsics #define _Compiler_or_memory_barrier() _Compiler_barrier() diff --git a/stl/inc/xatomic_wait.h b/stl/inc/xatomic_wait.h index 5058335d974..178f91fa9e8 100644 --- a/stl/inc/xatomic_wait.h +++ b/stl/inc/xatomic_wait.h @@ -21,9 +21,23 @@ _STL_DISABLE_CLANG_WARNINGS extern "C" { inline constexpr unsigned long __std_atomic_wait_no_timeout = 0xFFFF'FFFF; // Pass as partial timeout +enum class __std_atomic_api_level : unsigned long { + __not_set, + __detecting, + __has_srwlock, + __has_wait_on_address, +}; + +// This function allows testing the atomic wait support while always using the APIs for a platform with fewer +// capabilities; it attempts to lock the APIs used to the level `_Requested_api_level`, and returns the actual API level +// in use. Once the API level has been set by calling this function (or detected by a call to one of the atomic wait +// functions), it can no longer be changed. +__std_atomic_api_level __stdcall __std_atomic_set_api_level(__std_atomic_api_level _Requested_api_level) noexcept; + // Support for atomic waits. // The "direct" functions are used when the underlying infrastructure can use WaitOnAddress directly; that is, _Size is -// 1, 2, 4, or 8. The contract is the same as the WaitOnAddress function from the Windows SDK. +// 1, 2, 4, or 8. The contract is the same as the WaitOnAddress function from the Windows SDK. If WaitOnAddress is not +// available on the current platform, falls back to a similar solution based on SRWLOCK and CONDITION_VARIABLE. int __stdcall __std_atomic_wait_direct( const void* _Storage, void* _Comparand, size_t _Size, unsigned long _Remaining_timeout) noexcept; void __stdcall __std_atomic_notify_one_direct(const void* _Storage) noexcept; diff --git a/stl/inc/xfilesystem_abi.h b/stl/inc/xfilesystem_abi.h index 79ad2b66856..f11c87024c0 100644 --- a/stl/inc/xfilesystem_abi.h +++ b/stl/inc/xfilesystem_abi.h @@ -53,6 +53,7 @@ _NODISCARD inline bool __std_is_file_not_found(const __std_win_error _Error) noe case __std_win_error::_Path_not_found: case __std_win_error::_Error_bad_netpath: case __std_win_error::_Invalid_name: + case __std_win_error::_Directory_name_is_invalid: // Windows 11 24H2 return true; default: return false; diff --git a/stl/inc/xloctime b/stl/inc/xloctime index 52da0f5bae9..6926937743d 100644 --- a/stl/inc/xloctime +++ b/stl/inc/xloctime @@ -651,6 +651,21 @@ protected: __CLR_OR_THIS_CALL ~time_get_byname() noexcept override {} }; +// C23 7.29.3.5 "The strftime function"/3 +_INLINE_VAR constexpr char _Valid_strftime_specifiers[] = {'a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'F', 'g', 'G', + 'h', 'H', 'I', 'j', 'm', 'M', 'n', 'p', 'r', 'R', 'S', 't', 'T', 'u', 'U', 'V', 'w', 'W', 'x', 'X', 'y', 'Y', 'z', + 'Z'}; + +_NODISCARD constexpr bool _Is_valid_strftime_specifier(const char _Specifier) { + for (const auto& _Valid_specifier : _Valid_strftime_specifiers) { + if (_Specifier == _Valid_specifier) { + return true; + } + } + + return false; +} + _EXPORT_STD extern "C++" template >> class time_put : public locale::facet { // facet for converting encoded times to text public: @@ -687,7 +702,19 @@ public: _Specifier = _Ctype_fac.narrow(*_Fmtfirst); } - _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field + if (_Specifier == '%' && _Modifier == '\0') { + // if the specifier is percent and no modifier is set, just append it + *_Dest++ = _Percent; + } else if (!_Is_valid_strftime_specifier(_Specifier)) { + // no valid specifier, directly copy as literal elements + *_Dest++ = _Percent; + if (_Modifier != '\0') { + *_Dest++ = _Modifier; + } + *_Dest++ = _Specifier; + } else { + _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field + } } } @@ -811,7 +838,19 @@ public: _Specifier = _Ctype_fac.narrow(*_Fmtfirst); } - _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field + if (_Specifier == '%' && _Modifier == '\0') { + // if the specifier is percent and no modifier is set, just append it + *_Dest++ = _Percent; + } else if (!_Is_valid_strftime_specifier(_Specifier)) { + // no valid specifier, directly copy as literal elements + *_Dest++ = _Percent; + if (_Modifier != '\0') { + *_Dest++ = _Raw; + } + *_Dest++ = *_Fmtfirst; + } else { + _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field + } } } @@ -927,14 +966,15 @@ public: *_Dest++ = _Fmtfirst[-1]; break; } else { // get specifier after % - char _Specifier = _Ctype_fac.narrow(*_Fmtfirst); + _Elem _Raw = *_Fmtfirst; + char _Specifier = _Ctype_fac.narrow(_Raw); char _Modifier = '\0'; _Elem _Percent = _Fmtfirst[-1]; if (_Specifier == 'E' || _Specifier == 'O' || _Specifier == 'Q' || _Specifier == '#') { if (++_Fmtfirst == _Fmtlast) { // no specifier, copy %[E0Q#] as literal elements *_Dest++ = _Percent; - *_Dest++ = _Specifier; + *_Dest++ = _Raw; break; } @@ -943,7 +983,19 @@ public: _Specifier = _Ctype_fac.narrow(*_Fmtfirst); } - _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field + if (_Specifier == '%' && _Modifier == '\0') { + // if the specifier is percent and no modifier is set, just append it + *_Dest++ = _Percent; + } else if (!_Is_valid_strftime_specifier(_Specifier)) { + // no valid specifier, directly copy as literal elements + *_Dest++ = _Percent; + if (_Modifier != '\0') { + *_Dest++ = _Raw; + } + *_Dest++ = *_Fmtfirst; + } else { + _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field + } } } diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 011c0722780..45913c396c3 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1905,15 +1905,15 @@ _CONSTEXPR20 _Alloc_ptr_t<_Alloc> _Uninitialized_move( // move [_First, _Last) to raw _Dest, using _Al // note: only called internally from elsewhere in the STL using _Ptrval = typename _Alloc::value_type*; - auto _UFirst = _Get_unwrapped(_First); - const auto _ULast = _Get_unwrapped(_Last); + auto _UFirst = _STD _Get_unwrapped(_First); + const auto _ULast = _STD _Get_unwrapped(_Last); if constexpr (conjunction_v::_Bitcopy_constructible>, _Uses_default_construct<_Alloc, _Ptrval, decltype(_STD move(*_UFirst))>>) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 { - _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); + _STD _Copy_memmove(_UFirst, _ULast, _STD _Unfancy(_Dest)); return _Dest + (_ULast - _UFirst); } } diff --git a/stl/inc/xthreads.h b/stl/inc/xthreads.h index 09dad03f55e..de50b11a5e5 100644 --- a/stl/inc/xthreads.h +++ b/stl/inc/xthreads.h @@ -62,7 +62,8 @@ _CRTIMP2_PURE _Thrd_result __cdecl _Cnd_signal(_Cnd_t) noexcept; // TRANSITION, _CRTIMP2_PURE void __cdecl _Cnd_register_at_thread_exit(_Cnd_t, _Mtx_t, int*) noexcept; _CRTIMP2_PURE void __cdecl _Cnd_unregister_at_thread_exit(_Mtx_t) noexcept; _CRTIMP2_PURE void __cdecl _Cnd_do_broadcast_at_thread_exit() noexcept; -_Thrd_result __stdcall _Cnd_timedwait_for(_Cnd_t, _Mtx_t, unsigned int) noexcept; +// '_unchecked' means it is not checked against the 'steady_clock', so may report timeout prematurely +_Thrd_result __stdcall _Cnd_timedwait_for_unchecked(_Cnd_t, _Mtx_t, unsigned int) noexcept; } // extern "C" _STD_BEGIN diff --git a/stl/inc/xtr1common b/stl/inc/xtr1common index 02ea58bc094..b1829b8b323 100644 --- a/stl/inc/xtr1common +++ b/stl/inc/xtr1common @@ -152,14 +152,14 @@ struct _Disjunction { // handle true trait or last trait template struct _Disjunction { // first trait is false, try the next trait - using type = typename _Disjunction<_Next::value, _Next, _Rest...>::type; + using type = typename _Disjunction(_Next::value), _Next, _Rest...>::type; }; _EXPORT_STD template struct disjunction : false_type {}; // If _Traits is empty, false_type template -struct disjunction<_First, _Rest...> : _Disjunction<_First::value, _First, _Rest...>::type { +struct disjunction<_First, _Rest...> : _Disjunction(_First::value), _First, _Rest...>::type { // the first true trait in _Traits, or the last trait if none are true }; diff --git a/stl/inc/xutility b/stl/inc/xutility index fbed6751ec2..110178e1416 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -23,8 +23,10 @@ _STL_DISABLE_CLANG_WARNINGS // TRANSITION, non-_Ugly attribute tokens #pragma push_macro("msvc") #pragma push_macro("intrinsic") +#pragma push_macro("lifetimebound") #undef msvc #undef intrinsic +#undef lifetimebound #if defined(_CRTBLD) && defined(CRTDLL2) // TRANSITION, ABI: The vector algorithms are compiled into the import lib, so we disable their usage when building @@ -5824,6 +5826,10 @@ using _Lex_compare_three_way_memcmp_classify = _EXPORT_STD template _NODISCARD constexpr auto lexicographical_compare_three_way(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, const _InIt2 _Last2, _Cmp _Comp) -> decltype(_Comp(*_First1, *_First2)) { + static_assert( + _Classify_category != _Comparison_category::_Comparison_category_none, + "The result of the comparator must have comparison category type (N4988 [alg.three.way]/2)."); + _STD _Adl_verify_range(_First1, _Last1); _STD _Adl_verify_range(_First2, _Last2); auto _UFirst1 = _STD _Get_unwrapped(_First1); @@ -6953,8 +6959,8 @@ namespace ranges { public: template > _Pr = ranges::less> - _NODISCARD _STATIC_CALL_OPERATOR constexpr const _Ty& operator()( - const _Ty& _Left, const _Ty& _Right, _Pr _Pred = {}, _Pj _Proj = {}) _CONST_CALL_OPERATOR { + _NODISCARD _STATIC_CALL_OPERATOR constexpr const _Ty& operator()(const _Ty& _Left _MSVC_LIFETIMEBOUND, + const _Ty& _Right _MSVC_LIFETIMEBOUND, _Pr _Pred = {}, _Pj _Proj = {}) _CONST_CALL_OPERATOR { if (_STD invoke(_Pred, _STD invoke(_Proj, _Left), _STD invoke(_Proj, _Right))) { return _Right; } else { @@ -7171,8 +7177,8 @@ namespace ranges { public: template > _Pr = ranges::less> - _NODISCARD _STATIC_CALL_OPERATOR constexpr const _Ty& operator()( - const _Ty& _Left, const _Ty& _Right, _Pr _Pred = {}, _Pj _Proj = {}) _CONST_CALL_OPERATOR { + _NODISCARD _STATIC_CALL_OPERATOR constexpr const _Ty& operator()(const _Ty& _Left _MSVC_LIFETIMEBOUND, + const _Ty& _Right _MSVC_LIFETIMEBOUND, _Pr _Pred = {}, _Pj _Proj = {}) _CONST_CALL_OPERATOR { if (_STD invoke(_Pred, _STD invoke(_Proj, _Right), _STD invoke(_Proj, _Left))) { return _Right; } else { @@ -7425,6 +7431,7 @@ _NODISCARD constexpr bool _Mul_overflow(const _Int _Left, const _Int _Right, _In _STD_END // TRANSITION, non-_Ugly attribute tokens +#pragma pop_macro("lifetimebound") #pragma pop_macro("intrinsic") #pragma pop_macro("msvc") diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 9d8c99da832..b079e79e09c 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -361,7 +361,6 @@ // P2273R3 constexpr unique_ptr // P2278R4 cbegin Should Always Return A Constant Iterator // P2286R8 Formatting Ranges -// (only the '?' format specifier for strings and characters) // P2291R3 constexpr Integral // P2302R4 ranges::contains, ranges::contains_subrange // P2321R2 zip @@ -385,6 +384,7 @@ // P2539R4 Synchronizing print() With The Underlying Stream // P2540R1 Empty Product For Certain Views // P2549R1 unexpected::error() +// P2585R1 Improve Default Container Formatting // P2599R2 mdspan: index_type, size_type // P2604R0 mdspan: data_handle_type, data_handle(), exhaustive // P2613R1 mdspan: empty() @@ -885,7 +885,7 @@ #define _CPPLIB_VER 650 #define _MSVC_STL_VERSION 143 -#define _MSVC_STL_UPDATE 202407L +#define _MSVC_STL_UPDATE 202408L #ifndef _ALLOW_COMPILER_AND_STL_VERSION_MISMATCH #if defined(__CUDACC__) && defined(__CUDACC_VER_MAJOR__) @@ -1758,6 +1758,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_containers_ranges 202202L #define __cpp_lib_expected 202211L #define __cpp_lib_flat_map 202207L +#define __cpp_lib_format_ranges 202207L #define __cpp_lib_formatters 202302L #define __cpp_lib_forward_like 202207L #define __cpp_lib_freestanding_expected 202311L @@ -1941,6 +1942,7 @@ compiler option, or define _ALLOW_RTCc_IN_STL to suppress this error. #endif // defined(MRTDLL) && !defined(_M_CEE_PURE) #define _STL_WIN32_WINNT_VISTA 0x0600 // _WIN32_WINNT_VISTA from sdkddkver.h +#define _STL_WIN32_WINNT_WIN7 0x0601 // _WIN32_WINNT_WIN7 from sdkddkver.h #define _STL_WIN32_WINNT_WIN8 0x0602 // _WIN32_WINNT_WIN8 from sdkddkver.h #define _STL_WIN32_WINNT_WIN10 0x0A00 // _WIN32_WINNT_WIN10 from sdkddkver.h @@ -1949,10 +1951,13 @@ compiler option, or define _ALLOW_RTCc_IN_STL to suppress this error. #if defined(_M_ARM64) // The first ARM64 Windows was Windows 10 #define _STL_WIN32_WINNT _STL_WIN32_WINNT_WIN10 -#else // ^^^ defined(_M_ARM64) / !defined(_M_ARM64) vvv -// The earliest Windows supported by this implementation is Windows 8 +#elif defined(_M_ARM) || defined(_ONECORE) || defined(_CRT_APP) +// The first ARM or OneCore or App Windows was Windows 8 #define _STL_WIN32_WINNT _STL_WIN32_WINNT_WIN8 -#endif // ^^^ !defined(_M_ARM64) ^^^ +#else // ^^^ default to Win8 / default to Win7 vvv +// The earliest Windows supported by this implementation is Windows 7 +#define _STL_WIN32_WINNT _STL_WIN32_WINNT_WIN7 +#endif // ^^^ !defined(_M_ARM) && !defined(_M_ARM64) && !defined(_ONECORE) && !defined(_CRT_APP) ^^^ #endif // !defined(_STL_WIN32_WINNT) #ifdef __cpp_noexcept_function_type diff --git a/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets b/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets index 0f29c995877..869f8a1ecd2 100644 --- a/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets +++ b/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets @@ -70,7 +70,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/atomic_wait.cpp b/stl/src/atomic_wait.cpp index 4bafb1a86bb..2ac108c9988 100644 --- a/stl/src/atomic_wait.cpp +++ b/stl/src/atomic_wait.cpp @@ -11,8 +11,6 @@ #include -#pragma comment(lib, "synchronization") - namespace { constexpr unsigned long long _Atomic_wait_no_deadline = 0xFFFF'FFFF'FFFF'FFFF; @@ -91,13 +89,134 @@ namespace { } #endif // defined(_DEBUG) } + +#ifndef _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE +#if _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8 +#define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 1 +#else // ^^^ _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8 / _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 vvv +#define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 0 +#endif // ^^^ _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 ^^^ +#endif // !defined(_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE) + +#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE + +#pragma comment(lib, "synchronization") + +#define __crtWaitOnAddress WaitOnAddress +#define __crtWakeByAddressSingle WakeByAddressSingle +#define __crtWakeByAddressAll WakeByAddressAll + +#else // ^^^ _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE / !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE vvv + + struct _Wait_functions_table { + _STD atomic _Pfn_WaitOnAddress{nullptr}; + _STD atomic _Pfn_WakeByAddressSingle{nullptr}; + _STD atomic _Pfn_WakeByAddressAll{nullptr}; + _STD atomic<__std_atomic_api_level> _Api_level{__std_atomic_api_level::__not_set}; + }; + + _Wait_functions_table _Wait_functions; + + void _Force_wait_functions_srwlock_only() noexcept { + auto _Local = _Wait_functions._Api_level.load(_STD memory_order_acquire); + if (_Local <= __std_atomic_api_level::__detecting) { + while (!_Wait_functions._Api_level.compare_exchange_weak( + _Local, __std_atomic_api_level::__has_srwlock, _STD memory_order_acq_rel)) { + if (_Local > __std_atomic_api_level::__detecting) { + return; + } + } + } + } + + [[nodiscard]] __std_atomic_api_level _Init_wait_functions(__std_atomic_api_level _Level) { + while (!_Wait_functions._Api_level.compare_exchange_weak( + _Level, __std_atomic_api_level::__detecting, _STD memory_order_acq_rel)) { + if (_Level > __std_atomic_api_level::__detecting) { + return _Level; + } + } + + _Level = __std_atomic_api_level::__has_srwlock; + + const HMODULE _Sync_module = GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"); + if (_Sync_module != nullptr) { + const auto _Wait_on_address = + reinterpret_cast(GetProcAddress(_Sync_module, "WaitOnAddress")); + const auto _Wake_by_address_single = + reinterpret_cast(GetProcAddress(_Sync_module, "WakeByAddressSingle")); + const auto _Wake_by_address_all = + reinterpret_cast(GetProcAddress(_Sync_module, "WakeByAddressAll")); + + if (_Wait_on_address != nullptr && _Wake_by_address_single != nullptr && _Wake_by_address_all != nullptr) { + _Wait_functions._Pfn_WaitOnAddress.store(_Wait_on_address, _STD memory_order_relaxed); + _Wait_functions._Pfn_WakeByAddressSingle.store(_Wake_by_address_single, _STD memory_order_relaxed); + _Wait_functions._Pfn_WakeByAddressAll.store(_Wake_by_address_all, _STD memory_order_relaxed); + _Level = __std_atomic_api_level::__has_wait_on_address; + } + } + + // for __has_srwlock, relaxed would have been enough, not distinguishing for consistency + _Wait_functions._Api_level.store(_Level, _STD memory_order_release); + return _Level; + } + + [[nodiscard]] __std_atomic_api_level _Acquire_wait_functions() noexcept { + auto _Level = _Wait_functions._Api_level.load(_STD memory_order_acquire); + if (_Level <= __std_atomic_api_level::__detecting) { + _Level = _Init_wait_functions(_Level); + } + + return _Level; + } + + [[nodiscard]] BOOL __crtWaitOnAddress( + volatile VOID* Address, PVOID CompareAddress, SIZE_T AddressSize, DWORD dwMilliseconds) { + const auto _Wait_on_address = _Wait_functions._Pfn_WaitOnAddress.load(_STD memory_order_relaxed); + return _Wait_on_address(Address, CompareAddress, AddressSize, dwMilliseconds); + } + + VOID __crtWakeByAddressSingle(PVOID Address) { + const auto _Wake_by_address_single = _Wait_functions._Pfn_WakeByAddressSingle.load(_STD memory_order_relaxed); + _Wake_by_address_single(Address); + } + + VOID __crtWakeByAddressAll(PVOID Address) { + const auto _Wake_by_address_all = _Wait_functions._Pfn_WakeByAddressAll.load(_STD memory_order_relaxed); + _Wake_by_address_all(Address); + } + + bool __stdcall _Atomic_wait_are_equal_direct_fallback( + const void* _Storage, void* _Comparand, size_t _Size, void*) noexcept { + switch (_Size) { + case 1: + return __iso_volatile_load8(static_cast(_Storage)) == *static_cast(_Comparand); + case 2: + return __iso_volatile_load16(static_cast(_Storage)) == *static_cast(_Comparand); + case 4: + return __iso_volatile_load32(static_cast(_Storage)) == *static_cast(_Comparand); + case 8: + return __iso_volatile_load64(static_cast(_Storage)) + == *static_cast(_Comparand); + default: + _CSTD abort(); + } + } +#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE } // unnamed namespace extern "C" { int __stdcall __std_atomic_wait_direct(const void* const _Storage, void* const _Comparand, const size_t _Size, const unsigned long _Remaining_timeout) noexcept { - const auto _Result = - WaitOnAddress(const_cast(_Storage), const_cast(_Comparand), _Size, _Remaining_timeout); +#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 + if (_Acquire_wait_functions() < __std_atomic_api_level::__has_wait_on_address) { + return __std_atomic_wait_indirect( + _Storage, _Comparand, _Size, nullptr, &_Atomic_wait_are_equal_direct_fallback, _Remaining_timeout); + } +#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 + + const auto _Result = __crtWaitOnAddress( + const_cast(_Storage), const_cast(_Comparand), _Size, _Remaining_timeout); if (!_Result) { _Assume_timeout(); @@ -106,11 +225,25 @@ int __stdcall __std_atomic_wait_direct(const void* const _Storage, void* const _ } void __stdcall __std_atomic_notify_one_direct(const void* const _Storage) noexcept { - WakeByAddressSingle(const_cast(_Storage)); +#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 + if (_Acquire_wait_functions() < __std_atomic_api_level::__has_wait_on_address) { + __std_atomic_notify_one_indirect(_Storage); + return; + } +#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE = 0 + + __crtWakeByAddressSingle(const_cast(_Storage)); } void __stdcall __std_atomic_notify_all_direct(const void* const _Storage) noexcept { - WakeByAddressAll(const_cast(_Storage)); +#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 + if (_Acquire_wait_functions() < __std_atomic_api_level::__has_wait_on_address) { + __std_atomic_notify_all_indirect(_Storage); + return; + } +#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 + + __crtWakeByAddressAll(const_cast(_Storage)); } void __stdcall __std_atomic_notify_one_indirect(const void* const _Storage) noexcept { @@ -206,10 +339,25 @@ unsigned long __stdcall __std_atomic_wait_get_remaining_timeout(unsigned long lo return static_cast(_Remaining); } -// TRANSITION, ABI: preserved for binary compatibility -enum class __std_atomic_api_level : unsigned long { __not_set, __detecting, __has_srwlock, __has_wait_on_address }; -__std_atomic_api_level __stdcall __std_atomic_set_api_level(__std_atomic_api_level) noexcept { +__std_atomic_api_level __stdcall __std_atomic_set_api_level(__std_atomic_api_level _Requested_api_level) noexcept { +#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE + (void) _Requested_api_level; return __std_atomic_api_level::__has_wait_on_address; +#else // ^^^ _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE / !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE vvv + switch (_Requested_api_level) { + case __std_atomic_api_level::__not_set: + case __std_atomic_api_level::__detecting: + _CSTD abort(); + case __std_atomic_api_level::__has_srwlock: + _Force_wait_functions_srwlock_only(); + break; + case __std_atomic_api_level::__has_wait_on_address: + default: // future compat: new header using an old DLL will get the highest requested level supported + break; + } + + return _Acquire_wait_functions(); +#endif // !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE } #pragma warning(push) diff --git a/stl/src/awint.hpp b/stl/src/awint.hpp index 797801b7a98..da1e26e470a 100644 --- a/stl/src/awint.hpp +++ b/stl/src/awint.hpp @@ -14,6 +14,17 @@ _CRT_BEGIN_C_HEADER +#if _STL_WIN32_WINNT >= _WIN32_WINNT_WIN8 + +#define __crtGetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime) \ + GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime) + +#else // ^^^ _STL_WIN32_WINNT >= _WIN32_WINNT_WIN8 / _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 vvv + +_CRTIMP2 void __cdecl __crtGetSystemTimePreciseAsFileTime(_Out_ LPFILETIME lpSystemTimeAsFileTime) noexcept; + +#endif // ^^^ _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 ^^^ + _CRTIMP2 int __cdecl __crtCompareStringA(_In_z_ LPCWSTR _LocaleName, _In_ DWORD _DwCmpFlags, _In_reads_(_CchCount1) LPCSTR _LpString1, _In_ int _CchCount1, _In_reads_(_CchCount2) LPCSTR _LpString2, _In_ int _CchCount2, _In_ int _CodePage) noexcept; diff --git a/stl/src/ppltasks.cpp b/stl/src/ppltasks.cpp index 62cf885e54a..ef1048cad14 100644 --- a/stl/src/ppltasks.cpp +++ b/stl/src/ppltasks.cpp @@ -26,6 +26,12 @@ namespace Concurrency { namespace details { [[noreturn]] _CRTIMP2 void __cdecl _ReportUnobservedException() { +#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_CRT_APP) && _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 + if (!IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE)) { + std::abort(); + } +#endif // ^^^ __fastfail conditionally available ^^^ + __fastfail(FAST_FAIL_INVALID_ARG); } diff --git a/stl/src/sharedmutex.cpp b/stl/src/sharedmutex.cpp index ecb73c754ca..fac73f1e388 100644 --- a/stl/src/sharedmutex.cpp +++ b/stl/src/sharedmutex.cpp @@ -41,25 +41,42 @@ void __stdcall _Thrd_sleep_for(const unsigned long ms) noexcept { // suspend cur Sleep(ms); } -_Thrd_result __stdcall _Cnd_timedwait_for(const _Cnd_t cond, const _Mtx_t mtx, const unsigned int target_ms) noexcept { - _Thrd_result res = _Thrd_result::_Success; - const auto start_ms = GetTickCount64(); +namespace { + _Thrd_result __stdcall _Cnd_timedwait_for_impl( + const _Cnd_t cond, const _Mtx_t mtx, const unsigned int target_ms, const bool checked) noexcept { + _Thrd_result res = _Thrd_result::_Success; + unsigned long long start_ms = 0; + + if (checked) { + start_ms = GetTickCount64(); + } - // TRANSITION: replace with _Mtx_clear_owner(mtx); - mtx->_Thread_id = -1; - --mtx->_Count; + // TRANSITION: replace with _Mtx_clear_owner(mtx); + mtx->_Thread_id = -1; + --mtx->_Count; - if (!_Primitive_wait_for(cond, mtx, target_ms)) { // report timeout - const auto end_ms = GetTickCount64(); - if (end_ms - start_ms >= target_ms) { - res = _Thrd_result::_Timedout; + if (!_Primitive_wait_for(cond, mtx, target_ms)) { // report timeout + if (!checked || GetTickCount64() - start_ms >= target_ms) { + res = _Thrd_result::_Timedout; + } } + // TRANSITION: replace with _Mtx_reset_owner(mtx); + mtx->_Thread_id = static_cast(GetCurrentThreadId()); + ++mtx->_Count; + + return res; } - // TRANSITION: replace with _Mtx_reset_owner(mtx); - mtx->_Thread_id = static_cast(GetCurrentThreadId()); - ++mtx->_Count; +} // namespace - return res; +// TRANSITION, ABI: preserved for compatibility +_Thrd_result __stdcall _Cnd_timedwait_for(const _Cnd_t cond, const _Mtx_t mtx, const unsigned int target_ms) noexcept { + return _Cnd_timedwait_for_impl(cond, mtx, target_ms, true); } +_Thrd_result __stdcall _Cnd_timedwait_for_unchecked( + const _Cnd_t cond, const _Mtx_t mtx, const unsigned int target_ms) noexcept { + return _Cnd_timedwait_for_impl(cond, mtx, target_ms, false); +} + + } // extern "C" diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index 2abf6bff8e4..44cca169203 100644 --- a/stl/src/vector_algorithms.cpp +++ b/stl/src/vector_algorithms.cpp @@ -2087,7 +2087,6 @@ namespace { _Advance_bytes(_First, sizeof(_Ty)); } -#pragma loop(no_vector) // TRANSITION, VSO-2093761: work around a compiler back-end assertion for (auto _Ptr = static_cast(_First); _Ptr != _Last; ++_Ptr) { if constexpr ((_Mode & _Mode_min) != 0) { if (*_Ptr < _Cur_min_val) { diff --git a/stl/src/winapisupp.cpp b/stl/src/winapisupp.cpp index de6f6ae4d29..747fe070d2a 100644 --- a/stl/src/winapisupp.cpp +++ b/stl/src/winapisupp.cpp @@ -14,6 +14,10 @@ namespace { // Use this macro for defining the following function pointers #define DEFINEFUNCTIONPOINTER(fn_name) decltype(&fn_name) __KERNEL32Function_##fn_name = nullptr +#if _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 + DEFINEFUNCTIONPOINTER(GetSystemTimePreciseAsFileTime); +#endif // _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 + DEFINEFUNCTIONPOINTER(GetTempPath2W); // Use this macro for caching a function pointer from a DLL @@ -154,9 +158,15 @@ extern "C" _CRTIMP2 BOOL __cdecl __crtSetFileInformationByHandle(_In_ HANDLE con #if _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 -// TRANSITION, ABI: preserved for binary compatibility extern "C" _CRTIMP2 void __cdecl __crtGetSystemTimePreciseAsFileTime(_Out_ LPFILETIME lpSystemTimeAsFileTime) noexcept { - GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime); + // use GetSystemTimePreciseAsFileTime if it is available (only on Windows 8+)... + IFDYNAMICGETCACHEDFUNCTION(GetSystemTimePreciseAsFileTime) { + pfGetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime); + return; + } + + // ...otherwise use GetSystemTimeAsFileTime. + GetSystemTimeAsFileTime(lpSystemTimeAsFileTime); } #endif // _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 @@ -186,6 +196,10 @@ static int __cdecl initialize_pointers() noexcept { HINSTANCE hKernel32 = GetModuleHandleW(L"kernel32.dll"); _Analysis_assume_(hKernel32); +#if _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 + STOREFUNCTIONPOINTER(hKernel32, GetSystemTimePreciseAsFileTime); +#endif // _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 + // Note that GetTempPath2W is defined as of Windows 10 Build 20348 (a server release) or Windows 11, // but there is no "_WIN32_WINNT_WIN11" constant, so we will always dynamically load it STOREFUNCTIONPOINTER(hKernel32, GetTempPath2W); diff --git a/stl/src/xtime.cpp b/stl/src/xtime.cpp index 7499f42e19d..c59d0fc73af 100644 --- a/stl/src/xtime.cpp +++ b/stl/src/xtime.cpp @@ -51,7 +51,7 @@ _CRTIMP2_PURE long long __cdecl _Xtime_get_ticks() noexcept { constexpr long long _Epoch = 0x19DB1DED53E8000LL; FILETIME ft; - GetSystemTimePreciseAsFileTime(&ft); + __crtGetSystemTimePreciseAsFileTime(&ft); return ((static_cast(ft.dwHighDateTime)) << 32) + static_cast(ft.dwLowDateTime) - _Epoch; } diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 5ae8f27917d..d1c69193af2 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -21,6 +21,8 @@ std/time/time.syn/formatter.year_month_day_last.pass.cpp:0 FAIL std/time/time.syn/formatter.year_month_day_last.pass.cpp:1 FAIL std/time/time.syn/formatter.year_month_weekday.pass.cpp:0 FAIL std/time/time.syn/formatter.year_month_weekday.pass.cpp:1 FAIL +std/time/time.syn/formatter.zoned_time.pass.cpp:0 FAIL +std/time/time.syn/formatter.zoned_time.pass.cpp:1 FAIL # LLVM-74756: [libc++][test] overload_compare_iterator doesn't support its claimed iterator_category std/utilities/memory/specialized.algorithms/uninitialized.copy/uninitialized_copy.pass.cpp FAIL @@ -32,13 +34,20 @@ std/utilities/format/format.range/format.range.formatter/format.functions.vforma std/utilities/format/format.range/format.range.fmtset/format.functions.format.pass.cpp FAIL std/utilities/format/format.range/format.range.fmtset/format.functions.vformat.pass.cpp FAIL -# LLVM-94907: [libc++][test] Avoid -Wunused-variable warnings in mutex tests -std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/default.pass.cpp:2 FAIL -std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.class/default.pass.cpp:2 FAIL -std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/default.pass.cpp:2 FAIL +# LLVM-100498: [libc++][test] alg.find.last tests assume that std::array iterators are pointers +std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp FAIL +std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if.pass.cpp FAIL +std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if_not.pass.cpp FAIL -# LLVM-95944: [libc++][test] thread.condition.condvar/notify_all.pass.cpp has a flaky timing assumption -std/thread/thread.condition/thread.condition.condvar/notify_all.pass.cpp SKIPPED +# LLVM-100502: [libc++][test] Bogus loops in time.cal.ymdlast.nonmembers/comparisons.pass.cpp +# Note: The :1 (ASAN) configuration doesn't run static analysis. +std/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.nonmembers/comparisons.pass.cpp:0 FAIL + +# LLVM-100504: [libc++][test] Fix Clang -Wunused-variable warnings in time.zone.members/to_sys.pass.cpp +std/time/time.zone/time.zone.timezone/time.zone.members/to_sys.pass.cpp:2 FAIL + +# LLVM-100506: [libc++][test] Precondition violation in rand.dist.uni.real/param_ctor.pass.cpp +std/numerics/rand/rand.dist/rand.dist.uni/rand.dist.uni.real/param_ctor.pass.cpp FAIL # Non-Standard regex behavior. # "It seems likely that the test is still non-conforming due to how libc++ handles the 'w' character class." @@ -49,9 +58,6 @@ std/re/re.traits/lookup_classname.pass.cpp FAIL std/input.output/iostreams.base/ios.base/ios.base.storage/iword.pass.cpp SKIPPED std/input.output/iostreams.base/ios.base/ios.base.storage/pword.pass.cpp SKIPPED -# allocator -std/utilities/memory/default.allocator/allocator.ctor.pass.cpp FAIL - # This test is passing non-BidirectionalIterators to std::prev. # LWG-3197 "std::prev should not require BidirectionalIterator" (New) std/iterators/iterator.primitives/iterator.operations/prev.pass.cpp FAIL @@ -79,6 +85,9 @@ std/numerics/rand/rand.util/rand.util.canonical/generate_canonical.pass.cpp FAIL # Test expects __cpp_lib_chrono to have the old value 201611L for P0505R0; we define the C++20 value 201907L for P1466R3. std/language.support/support.limits/support.limits.general/chrono.version.compile.pass.cpp FAIL +# Test expects __cpp_lib_three_way_comparison to have the old value 201711L for P0768R1; we define the C++20 value 201907L for P1614R2. +std/language.support/support.limits/support.limits.general/compare.version.compile.pass.cpp FAIL + # Tests expect __cpp_lib_ranges to have the old value 201811L for P0896R4; we define the C++20 value 201911L for P1716R3. std/language.support/support.limits/support.limits.general/algorithm.version.compile.pass.cpp FAIL std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp FAIL @@ -91,6 +100,7 @@ std/utilities/tuple/tuple.tuple/tuple.assign/const_pair.pass.cpp FAIL std/language.support/support.limits/support.limits.general/variant.version.compile.pass.cpp FAIL # libc++ has not implemented P2278R4: "cbegin should always return a constant iterator" +std/containers/views/views.span/span.cons/span.pass.cpp FAIL std/containers/views/views.span/types.pass.cpp FAIL std/ranges/range.access/begin.pass.cpp FAIL std/ranges/range.access/data.pass.cpp FAIL @@ -123,14 +133,6 @@ std/language.support/support.limits/support.limits.general/mdspan.version.compil # libc++ has not implemented P2937R0: "Freestanding Library: Remove strtok" std/language.support/support.limits/support.limits.general/cstring.version.compile.pass.cpp FAIL -# libc++ has not implemented P2997R1: "Removing The Common Reference Requirement From The Indirectly Invocable Concepts" -std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp FAIL -std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp FAIL -std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp FAIL -std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp FAIL -std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp FAIL -std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp FAIL - # Various bogosity (LLVM-D141004), warning C6011: Dereferencing NULL pointer # Note: The :1 (ASAN) configuration doesn't run static analysis. std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp:0 FAIL @@ -176,13 +178,6 @@ std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitiali std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer.value/ctor.default.pass.cpp FAIL std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer.value/ctor.iter.pass.cpp FAIL -# libc++ doesn't implement LWG-4061 -std/utilities/format/format.functions/bug_81590.compile.pass.cpp FAIL - -# libc++ doesn't implement LWG-4106 -std/utilities/format/format.arguments/format.args/ctor.pass.cpp FAIL -std/utilities/format/format.arguments/format.args/get.pass.cpp FAIL - # If any feature-test macro test is failing, this consolidated test will also fail. std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp FAIL @@ -233,6 +228,9 @@ std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pa std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp:1 SKIPPED std/input.output/syncstream/osyncstream/thread/several_threads.pass.cpp:1 SKIPPED +# VSO-2164191 "[ASAN][STL] Interception breaks strtoll" +std/strings/string.conversions/stoll.pass.cpp:1 FAIL + # *** MISSING STL FEATURES *** # Missing mbrtoc8 and c8rtomb @@ -246,14 +244,6 @@ std/language.support/support.limits/support.limits.general/cstdlib.version.compi # P2255R2 "Type Traits To Detect References Binding To Temporaries" std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp FAIL -# P2286R8 Formatting Ranges -std/containers/container.adaptors/container.adaptors.format/format.functions.format.pass.cpp FAIL -std/containers/container.adaptors/container.adaptors.format/format.functions.vformat.pass.cpp FAIL -std/containers/container.adaptors/container.adaptors.format/format.pass.cpp FAIL -std/containers/container.adaptors/container.adaptors.format/parse.pass.cpp FAIL -std/containers/container.adaptors/container.adaptors.format/types.compile.pass.cpp FAIL -std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp FAIL - # *** MISSING COMPILER FEATURES *** # P1169R4 static operator() @@ -323,7 +313,7 @@ std/utilities/utility/pairs/pairs.spec/three_way_comparison.pass.cpp:1 FAIL std/utilities/variant/variant.relops/three_way.pass.cpp:0 FAIL std/utilities/variant/variant.relops/three_way.pass.cpp:1 FAIL -# DevCom-1626727 VSO-1457307: bogus "failure was caused by a conversion from void* to a pointer-to-object type" for conversion to void +# VSO-2188243 constexpr ICE in C1XX adapt::to_prvalue std/algorithms/robust_re_difference_type.compile.pass.cpp:0 FAIL std/algorithms/robust_re_difference_type.compile.pass.cpp:1 FAIL @@ -350,7 +340,7 @@ std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_wit std/containers/sequences/array/array.cons/initialization.pass.cpp:0 FAIL std/containers/sequences/array/array.cons/initialization.pass.cpp:1 FAIL -# DevCom-10456523: MSVC incorrectly raises constant evaluation failure in pointer comparison +# DevCom-10456523 VSO-1880569: MSVC incorrectly raises constant evaluation failure in pointer comparison std/algorithms/robust_against_adl.compile.pass.cpp:0 FAIL std/algorithms/robust_against_adl.compile.pass.cpp:1 FAIL @@ -370,11 +360,21 @@ std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp:1 FAIL std/language.support/support.rtti/type.info/type_info.equal.pass.cpp:0 FAIL std/language.support/support.rtti/type.info/type_info.equal.pass.cpp:1 FAIL +# VSO-2170500 C1XX's type trait optimization mishandles conjunction/disjunction with non-bool types +std/utilities/meta/meta.logical/conjunction.compile.pass.cpp:0 FAIL +std/utilities/meta/meta.logical/conjunction.compile.pass.cpp:1 FAIL +std/utilities/meta/meta.logical/disjunction.compile.pass.cpp:0 FAIL +std/utilities/meta/meta.logical/disjunction.compile.pass.cpp:1 FAIL + # *** CLANG COMPILER BUGS *** # LLVM-46207 Clang's tgmath.h interferes with the UCRT's tgmath.h std/depr/depr.c.headers/tgmath_h.pass.cpp:2 FAIL +# LLVM-95311 [clang] __has_unique_object_representations gives inconsistent answer based on instantiation order +# A libc++ product code workaround (using `remove_all_extents_t`) and test coverage were added by LLVM-95314. +std/utilities/meta/meta.unary/meta.unary.prop/has_unique_object_representations.compile.pass.cpp:2 FAIL + # *** CLANG ISSUES, NOT YET ANALYZED *** # Clang doesn't enable sized deallocation by default. Should we add -fsized-deallocation or do something else? @@ -468,14 +468,6 @@ std/input.output/string.streams/stringbuf/stringbuf.members/view.pass.cpp FAIL std/input.output/syncstream/syncbuf/syncstream.syncbuf.cons/dtor.pass.cpp FAIL std/input.output/syncstream/syncbuf/syncstream.syncbuf.members/emit.pass.cpp FAIL -# GH-4723: : condition_variable_any::wait_for returns cv_status::timeout when the elapsed time is shorter than requested -std/thread/thread.condition/thread.condition.condvarany/notify_all.pass.cpp SKIPPED -std/thread/thread.condition/thread.condition.condvarany/notify_one.pass.cpp SKIPPED -std/thread/thread.condition/thread.condition.condvarany/wait_for_pred.pass.cpp SKIPPED -std/thread/thread.condition/thread.condition.condvarany/wait_for.pass.cpp SKIPPED -std/thread/thread.condition/thread.condition.condvarany/wait_until_pred.pass.cpp SKIPPED -std/thread/thread.condition/thread.condition.condvarany/wait_until.pass.cpp SKIPPED - # *** VCRUNTIME BUGS *** # DevCom-10373274 VSO-1824997 "vcruntime nothrow array operator new falls back on the wrong function" @@ -512,25 +504,17 @@ std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert. std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.single.pass.cpp FAIL std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp FAIL -# Not analyzed, likely bogus tests. Appears to be timing assumptions. +# `ALLOW_RETRIES` comments indicate tests with timing assumptions std/thread/futures/futures.async/async.pass.cpp SKIPPED -std/thread/futures/futures.shared_future/get.pass.cpp SKIPPED -std/thread/futures/futures.shared_future/wait.pass.cpp SKIPPED -std/thread/futures/futures.shared_future/wait_for.pass.cpp SKIPPED -std/thread/futures/futures.shared_future/wait_until.pass.cpp SKIPPED -std/thread/futures/futures.unique_future/get.pass.cpp SKIPPED -std/thread/futures/futures.unique_future/wait.pass.cpp SKIPPED std/thread/futures/futures.unique_future/wait_for.pass.cpp SKIPPED -std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex_duration.pass.cpp SKIPPED -std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex_time_point.pass.cpp SKIPPED +std/thread/thread.condition/thread.condition.condvarany/notify_one.pass.cpp SKIPPED std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex_try_to_lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex.pass.cpp SKIPPED -std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.locking/lock.pass.cpp SKIPPED std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_duration.pass.cpp SKIPPED std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_time_point.pass.cpp SKIPPED std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_try_to_lock.pass.cpp SKIPPED std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex.pass.cpp SKIPPED std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/lock.pass.cpp SKIPPED +std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock.pass.cpp SKIPPED std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/lock.pass.cpp SKIPPED std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/try_lock.pass.cpp SKIPPED std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/lock.pass.cpp SKIPPED @@ -555,6 +539,18 @@ std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/try_lock_for.pass.cpp SKIPPED std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/try_lock_until.pass.cpp SKIPPED std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/try_lock.pass.cpp SKIPPED + +# Not analyzed, likely bogus tests. Appears to be timing assumptions. +std/thread/futures/futures.shared_future/get.pass.cpp SKIPPED +std/thread/futures/futures.shared_future/wait.pass.cpp SKIPPED +std/thread/futures/futures.shared_future/wait_for.pass.cpp SKIPPED +std/thread/futures/futures.shared_future/wait_until.pass.cpp SKIPPED +std/thread/futures/futures.unique_future/get.pass.cpp SKIPPED +std/thread/futures/futures.unique_future/wait.pass.cpp SKIPPED +std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex_duration.pass.cpp SKIPPED +std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex_time_point.pass.cpp SKIPPED +std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex.pass.cpp SKIPPED +std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.locking/lock.pass.cpp SKIPPED std/thread/thread.threads/thread.thread.this/sleep_until.pass.cpp SKIPPED # Not analyzed, likely bogus tests. Various assertions, probably POSIX assumptions. @@ -585,10 +581,6 @@ std/numerics/complex.number/cmplx.over/proj.pass.cpp:1 FAIL # libc++ handles those input values differently std/numerics/complex.number/complex.value.ops/polar.pass.cpp FAIL -# Assertion failed: invalid min and max arguments for uniform_real -# `param_type p(5);` is a precondition violation. -std/numerics/rand/rand.dist/rand.dist.uni/rand.dist.uni.real/param_ctor.pass.cpp FAIL - # Assertion failed: invalid beta argument for gamma_distribution # test4() constructs a negative_binomial_distribution from (40, 1); [rand.dist.bern.negbin] says p == 1 generates undefined probabilities. std/numerics/rand/rand.dist/rand.dist.bern/rand.dist.bern.negbin/eval.pass.cpp FAIL @@ -646,7 +638,6 @@ std/re/re.traits/lookup_collatename.pass.cpp FAIL std/re/re.traits/transform_primary.pass.cpp FAIL # Not analyzed, likely STL bugs. Various assertions. -std/numerics/complex.number/complex.member.ops/divide_equal_complex.pass.cpp FAIL std/numerics/complex.number/complex.ops/complex_divide_complex.pass.cpp FAIL std/numerics/complex.number/complex.ops/complex_times_complex.pass.cpp FAIL std/numerics/complex.number/complex.ops/scalar_divide_complex.pass.cpp FAIL @@ -905,12 +896,6 @@ std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_swap.pass # Not analyzed. Checking whether packaged_task is constructible from an allocator and a packaged_task of a different type. std/thread/futures/futures.task/futures.task.members/ctor2.compile.pass.cpp FAIL -# Not analyzed. -# MSVC warning C4305: 'specialization': truncation from 'const int' to 'bool' -# Clang error: non-type template argument evaluates to -1, which cannot be narrowed to type 'bool' [-Wc++11-narrowing] -std/utilities/meta/meta.logical/conjunction.compile.pass.cpp FAIL -std/utilities/meta/meta.logical/disjunction.compile.pass.cpp FAIL - # Not analyzed. Possible MSVC compiler bug, this is inspecting type trait behavior. std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_copy_assignable.pass.cpp:0 FAIL std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_copy_assignable.pass.cpp:1 FAIL @@ -976,6 +961,7 @@ std/input.output/string.streams/stringstream/stringstream.members/str.allocator_ # These formatter tests need to create basic_format_contexts, so test_format_context.h # says "Please create a vendor specific version of the test functions". # If we do, some of these tests should be able to work. +std/containers/container.adaptors/container.adaptors.format/format.pass.cpp FAIL std/containers/sequences/vector.bool/vector.bool.fmt/format.pass.cpp FAIL std/thread/thread.threads/thread.thread.class/thread.thread.id/format.pass.cpp FAIL std/utilities/format/format.formatter/format.context/format.context/advance_to.pass.cpp FAIL @@ -1006,22 +992,15 @@ std/utilities/format/format.range/format.range.fmtset/format.pass.cpp FAIL std/utilities/format/format.range/format.range.fmtstr/format.pass.cpp FAIL std/utilities/format/format.tuple/format.pass.cpp FAIL -# Not analyzed. Apparent false positives from static analysis where it thinks that array indexing is out of bounds. -# warning C28020: The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call. +# Not analyzed. Static analysis thinks that array indexing is out of bounds because it can't prove otherwise. +# warning C28020: The expression '_Param_(1)<1' is not true at this call. # Note: The :1 (ASAN) configuration doesn't run static analysis. std/containers/views/mdspan/extents/ctor_default.pass.cpp:0 FAIL std/containers/views/mdspan/extents/ctor_from_array.pass.cpp:0 FAIL std/containers/views/mdspan/extents/ctor_from_integral.pass.cpp:0 FAIL std/containers/views/mdspan/extents/ctor_from_span.pass.cpp:0 FAIL -std/containers/views/mdspan/layout_left/ctor.layout_stride.pass.cpp:0 FAIL -std/containers/views/mdspan/layout_left/stride.pass.cpp:0 FAIL -std/containers/views/mdspan/layout_right/ctor.layout_stride.pass.cpp:0 FAIL -std/containers/views/mdspan/layout_right/stride.pass.cpp:0 FAIL -std/containers/views/mdspan/layout_stride/ctor.default.pass.cpp:0 FAIL -std/containers/views/mdspan/layout_stride/ctor.extents_array.pass.cpp:0 FAIL -std/containers/views/mdspan/layout_stride/ctor.extents_span.pass.cpp:0 FAIL +std/containers/views/mdspan/layout_stride/comparison.pass.cpp:0 FAIL std/containers/views/mdspan/layout_stride/ctor.strided_mapping.pass.cpp:0 FAIL -std/containers/views/mdspan/layout_stride/stride.pass.cpp:0 FAIL std/containers/views/mdspan/mdspan/conversion.pass.cpp:0 FAIL std/containers/views/mdspan/mdspan/ctor.dh_array.pass.cpp:0 FAIL std/containers/views/mdspan/mdspan/ctor.dh_span.pass.cpp:0 FAIL @@ -1050,6 +1029,7 @@ std/time/time.syn/formatter.file_time.pass.cpp:2 FAIL std/time/time.syn/formatter.hh_mm_ss.pass.cpp:2 FAIL std/time/time.syn/formatter.local_time.pass.cpp:2 FAIL std/time/time.syn/formatter.sys_time.pass.cpp:2 FAIL +std/time/time.syn/formatter.zoned_time.pass.cpp:2 FAIL # Not analyzed. constexpr evaluation fails with "vector iterators incompatible". std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp:0 FAIL @@ -1099,6 +1079,8 @@ std/algorithms/alg.modifying.operations/alg.transform/ranges.transform.binary.ra std/algorithms/alg.modifying.operations/alg.transform/ranges.transform.binary.range.pass.cpp:1 SKIPPED std/algorithms/alg.nonmodifying/alg.ends_with/ranges.ends_with.pass.cpp:0 SKIPPED std/algorithms/alg.nonmodifying/alg.ends_with/ranges.ends_with.pass.cpp:1 SKIPPED +std/algorithms/alg.sorting/alg.lex.comparison/ranges.lexicographical_compare.pass.cpp:0 SKIPPED +std/algorithms/alg.sorting/alg.lex.comparison/ranges.lexicographical_compare.pass.cpp:1 SKIPPED std/algorithms/alg.sorting/alg.merge/ranges_merge.pass.cpp:0 SKIPPED std/algorithms/alg.sorting/alg.merge/ranges_merge.pass.cpp:1 SKIPPED std/algorithms/alg.sorting/alg.set.operations/includes/ranges_includes.pass.cpp:0 SKIPPED @@ -1219,9 +1201,6 @@ std/time/time.zone/time.zone.leap/members/date.pass.cpp FAIL std/time/time.zone/time.zone.leap/members/value.pass.cpp FAIL std/time/time.zone/time.zone.leap/nonmembers/comparison.pass.cpp FAIL -# Not analyzed. Assertion failed: tzdb.leap_seconds.size() >= leap_seconds.size() -std/time/time.zone/time.zone.db/leap_seconds.pass.cpp FAIL - # Not analyzed. Assertion failed: tz->name() == zone std/time/time.zone/time.zone.db/time.zone.db.access/current_zone.pass.cpp FAIL std/time/time.zone/time.zone.db/time.zone.db.tzdb/current_zone.pass.cpp FAIL @@ -1262,6 +1241,33 @@ std/atomics/atomics.ref/operator_plus_equals.pass.cpp SKIPPED std/atomics/atomics.ref/store.pass.cpp SKIPPED std/atomics/atomics.ref/wait.pass.cpp SKIPPED +# Not analyzed. Attempting to dereference `void *`. +std/utilities/memory/unique.ptr/noexcept_operator_star.compile.pass.cpp FAIL +std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/dereference.single.pass.cpp FAIL + +# Not analyzed. Attempting to delete `nullptr_t`. +std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter.pass.cpp FAIL + +# Not analyzed. Various assertions. +std/time/time.zone/time.zone.timezone/time.zone.members/get_info.local_time.pass.cpp FAIL +std/time/time.zone/time.zone.timezone/time.zone.members/to_sys_choose.pass.cpp FAIL +std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/get_info.pass.cpp FAIL +std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.nonmembers/ostream.pass.cpp FAIL + +# Not analyzed. static_assert(testComplexity()) is failing. +std/algorithms/alg.sorting/alg.set.operations/set.intersection/set_intersection_complexity.pass.cpp FAIL + +# Not analyzed. +# MSVC constexpr error: failure was caused by unexpected deallocation count +# Clang assertion: _CrtIsValidHeapPointer(block) +std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp FAIL +std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp FAIL + +# Not analyzed. +# MSVC truncation warnings. +# Clang assertion: std::hermite(n, +inf) == inf +std/numerics/c.math/hermite.pass.cpp FAIL + # *** XFAILs WHICH PASS *** # These tests contain `// XFAIL: msvc` comments, which accurately describe runtime failures for x86 and x64. @@ -1333,6 +1339,6 @@ std/input.output/string.streams/stringstream/stringstream.members/gcount.pass.cp # Similarly, this test is marked as `REQUIRES: 32-bit-pointer`. std/iterators/iterator.container/ssize.LWG3207.compile.pass.cpp:9 SKIPPED -# These tests are marked as "UNSUPPORTED: !has-unix-headers" with comments saying: -# "`check_assertion.h` requires Unix headers". -std/algorithms/pstl.exception_handling.pass.cpp:9 SKIPPED +# This test is marked as `REQUIRES: has-unix-headers, libcpp-has-abi-bounded-iterators-in-vector`. +# Listing these on separate lines would allow magic_comments.txt to recognize it. +std/containers/sequences/vector/vector.modifiers/assert.push_back.invalidation.pass.cpp:9 SKIPPED diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index cc09948b0ab..500d22be37a 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -251,7 +251,10 @@ MappingProperties get_mapping_properties(const Mapping& mapping) { constexpr auto rank = Mapping::extents_type::rank(); constexpr std::make_index_sequence rank_indices; - auto get_extent = [&](size_t i) { return mapping.extents().extent(i); }; + auto get_extent = [&](size_t i) { + assert(i < rank); + return mapping.extents().extent(i); + }; auto multidim_indices = [&](std::index_sequence) { return std::views::cartesian_product(std::views::iota(IndexType{0}, get_extent(Indices))...); }(rank_indices); diff --git a/tests/std/test.lst b/tests/std/test.lst index 7efa2749d27..b4814f55af5 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -236,6 +236,7 @@ tests\GH_003840_tellg_when_reading_lf_file_in_text_mode tests\GH_003867_output_nan tests\GH_004023_mdspan_fwd_prod_overflow tests\GH_004040_container_nonmember_functions +tests\GH_004108_some_ranges_algos_construct_wrong_type tests\GH_004109_iter_value_t_direct_initialization tests\GH_004129_conversion_in_new_numeric_algorithms tests\GH_004201_chrono_formatter @@ -247,6 +248,7 @@ tests\GH_004609_heterogeneous_cmp_overloads tests\GH_004618_mixed_operator_usage_keeps_statistical_properties tests\GH_004618_normal_distribution_avoids_resets tests\GH_004657_expected_constraints_permissive +tests\GH_004845_logical_operator_traits_with_non_bool_constant tests\LWG2381_num_get_floating_point tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function @@ -524,6 +526,7 @@ tests\P1032R1_miscellaneous_constexpr tests\P1132R7_out_ptr tests\P1135R6_atomic_flag_test tests\P1135R6_atomic_wait +tests\P1135R6_atomic_wait_win7 tests\P1135R6_barrier tests\P1135R6_latch tests\P1135R6_semaphore @@ -615,6 +618,7 @@ tests\P2278R4_const_span tests\P2278R4_ranges_const_iterator_machinery tests\P2278R4_ranges_const_range_machinery tests\P2278R4_views_as_const +tests\P2286R8_text_formatting_container_adaptors tests\P2286R8_text_formatting_debug_enabled_specializations tests\P2286R8_text_formatting_escaping tests\P2286R8_text_formatting_escaping_legacy_text_encoding @@ -756,4 +760,5 @@ tests\VSO_0849827_multicontainer_emplace_hint_position tests\VSO_0938757_attribute_order tests\VSO_0961751_hash_range_erase tests\VSO_0971246_legacy_await_headers +tests\VSO_1804139_static_analysis_warning_with_single_element_array tests\VSO_1925201_iter_traits diff --git a/tests/std/tests/Dev11_0836436_get_time/test.cpp b/tests/std/tests/Dev11_0836436_get_time/test.cpp index 7d2409b5225..ce5152ca1c9 100644 --- a/tests/std/tests/Dev11_0836436_get_time/test.cpp +++ b/tests/std/tests/Dev11_0836436_get_time/test.cpp @@ -110,6 +110,7 @@ void test_invalid_argument(); void test_buffer_resizing(); void test_gh_2618(); void test_gh_2848(); +void test_gh_4820(); int main() { assert(read_hour("12 AM") == 0); @@ -157,6 +158,7 @@ int main() { test_buffer_resizing(); test_gh_2618(); test_gh_2848(); + test_gh_4820(); } typedef istreambuf_iterator Iter; @@ -792,16 +794,17 @@ void test_invalid_argument() { time_t t = time(nullptr); tm currentTime; localtime_s(¤tTime, &t); + currentTime.tm_hour = 25; // set invalid hour { wstringstream wss; - wss << put_time(¤tTime, L"%Y-%m-%d-%H-%M-%s"); + wss << put_time(¤tTime, L"%Y-%m-%d-%H-%M"); assert(wss.rdstate() == ios_base::badbit); } { stringstream ss; - ss << put_time(¤tTime, "%Y-%m-%d-%H-%M-%s"); + ss << put_time(¤tTime, "%Y-%m-%d-%H-%M"); assert(ss.rdstate() == ios_base::badbit); } #endif // _M_CEE_PURE @@ -905,3 +908,39 @@ void test_gh_2848() { assert(err == (ios_base::eofbit | ios_base::failbit)); } } + +void test_gh_4820() { + // GH-4820 : std::put_time should copy unknown conversion specifiers instead of crash + time_t t = time(nullptr); + tm currentTime; + localtime_s(¤tTime, &t); + + // Case 1: Test various unknown conversion specifiers. + // Case 2: "%%" is a known escape sequence with a dedicated fast path. + // Case 3: "% " is percent followed by space, which is an unknown conversion specifier. + // Case 4: "%E%Z" is parsed as "%E%" followed by "Z", so it should be copied unchanged, + // even though "%Z" by itself would be a known conversion specifier (time zone name). + // (In case 1, "%E%J" is parsed the same way; the difference is that "%J" would be unknown.) + { + wstringstream wss; + wss << put_time(¤tTime, L"1:%Ei%!%E%J%P 2:%% 3:% 4:%E%Z"); + assert(wss.rdstate() == ios_base::goodbit); + assert(wss.str() == L"1:%Ei%!%E%J%P 2:% 3:% 4:%E%Z"); + } + + { + stringstream ss; + ss << put_time(¤tTime, "1:%Ei%!%E%J%P 2:%% 3:% 4:%E%Z"); + assert(ss.rdstate() == ios_base::goodbit); + assert(ss.str() == "1:%Ei%!%E%J%P 2:% 3:% 4:%E%Z"); + } + + // Also verify that wide characters aren't truncated. + // This tests a character appearing by itself, two as specifiers, and two as modified specifiers. + { + wstringstream wss; + wss << put_time(¤tTime, L"\x043a%\x043e%\x0448%E\x043a%O\x0430"); + assert(wss.rdstate() == ios_base::goodbit); + assert(wss.str() == L"\x043a%\x043e%\x0448%E\x043a%O\x0430"); + } +} diff --git a/tests/std/tests/GH_004108_some_ranges_algos_construct_wrong_type/env.lst b/tests/std/tests/GH_004108_some_ranges_algos_construct_wrong_type/env.lst new file mode 100644 index 00000000000..351a8293d9d --- /dev/null +++ b/tests/std/tests/GH_004108_some_ranges_algos_construct_wrong_type/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_20_matrix.lst diff --git a/tests/std/tests/GH_004108_some_ranges_algos_construct_wrong_type/test.compile.pass.cpp b/tests/std/tests/GH_004108_some_ranges_algos_construct_wrong_type/test.compile.pass.cpp new file mode 100644 index 00000000000..1ef17173110 --- /dev/null +++ b/tests/std/tests/GH_004108_some_ranges_algos_construct_wrong_type/test.compile.pass.cpp @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +using namespace std; + +namespace gh4108 { + struct RRef { + RRef(RRef&&) = delete; + }; + + struct Val { + Val(const RRef&); + auto operator<=>(const Val&) const = default; + }; + + struct I { + using value_type = Val; + using difference_type = ptrdiff_t; + Val& operator*() const; + I& operator++(); + I operator++(int); + I& operator--(); + I operator--(int); + bool operator==(const I&) const; + friend RRef&& iter_move(const I&); + }; + + // GH-4108 : ranges::inplace_merge accidentally constructed remove_cvref_t> + void test_gh_4108() { + ranges::inplace_merge(I{}, I{}, I{}); + } +} // namespace gh4108 + +namespace gh4102 { + struct Ref { + Ref(const Ref&) = delete; + auto operator<=>(const Ref&) const = default; + }; + + struct Val { + Val() = default; + Val(const Ref&); + auto operator<=>(const Val&) const = default; + }; + + struct I { + using value_type = Val; + using difference_type = ptrdiff_t; + const Ref& operator*() const; + I& operator++(); + void operator++(int); + bool operator==(const I&) const; + }; + + // GH-4102 : ranges::minmax accidentally constructed remove_cvref_t> + void test_gh_4102() { + [[maybe_unused]] auto result = ranges::minmax(ranges::subrange{}); + } +} // namespace gh4102 diff --git a/tests/std/tests/GH_004845_logical_operator_traits_with_non_bool_constant/env.lst b/tests/std/tests/GH_004845_logical_operator_traits_with_non_bool_constant/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_004845_logical_operator_traits_with_non_bool_constant/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_004845_logical_operator_traits_with_non_bool_constant/test.compile.pass.cpp b/tests/std/tests/GH_004845_logical_operator_traits_with_non_bool_constant/test.compile.pass.cpp new file mode 100644 index 00000000000..0f621d7f99f --- /dev/null +++ b/tests/std/tests/GH_004845_logical_operator_traits_with_non_bool_constant/test.compile.pass.cpp @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// GH-4845 : Logical operator traits with non-bool_constant arguments emit truncation warnings + +#include +using namespace std; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +template +void test_base_derived() { + STATIC_ASSERT(is_base_of_v); + using ValueType = typename Base::value_type; + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(Base::value == Derived::type::value); +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-2170500 (C1XX type trait optimization) + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(Base::value == Derived::value); +#endif // ^^^ no workaround ^^^ +} + +template +using SC = integral_constant; +template +using LC = integral_constant; + +// This test is verifying the absence of truncation warnings, so it uses integral values of 2 or greater for "true" +// values, skipping 1. It also tests these values in both the "first" and "next" positions, as they were both affected. + +void test_conjunction() { + // N4986 [meta.logical]/5: + // The specialization conjunction has a public and unambiguous base that is either + // - the first type Bi in the list true_type, B1, ..., BN for which bool(Bi::value) is false, or + // - if there is no such Bi, the last type in the list. + test_base_derived, conjunction, LC<3>>>(); + test_base_derived, conjunction, LC<0>>>(); + test_base_derived, conjunction, LC<5>>>(); + test_base_derived, conjunction, LC<0>>>(); +} + +void test_disjunction() { + // N4986 [meta.logical]/10: + // The specialization disjunction has a public and unambiguous base that is either + // - the first type Bi in the list false_type, B1, ..., BN for which bool(Bi::value) is true, or + // - if there is no such Bi, the last type in the list. + test_base_derived, disjunction, LC<7>>>(); + test_base_derived, disjunction, LC<0>>>(); + test_base_derived, disjunction, LC<9>>>(); + test_base_derived, disjunction, LC<0>>>(); +} + +void test_negation() { + // N4986 [meta.logical]/12: + // The class template negation forms the logical negation of its template type argument. + // The type negation is a Cpp17UnaryTypeTrait with a base characteristic of bool_constant. + test_base_derived>>(); + test_base_derived>>(); +} diff --git a/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp b/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp index 6565c43abe7..bdb9279c6af 100644 --- a/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp @@ -16,13 +16,19 @@ using namespace std; void test_static_extent_function_with_invalid_index() { using E = extents; // Index must be less than rank() +#pragma warning(push) +#pragma warning(disable : 28020) // yay, /analyze catches this mistake at compile time! (void) E::static_extent(1); +#pragma warning(pop) } void test_extent_function_with_invalid_index() { extents e; // Index must be less than rank() +#pragma warning(push) +#pragma warning(disable : 28020) // yay, /analyze catches this mistake at compile time! (void) e.extent(1); +#pragma warning(pop) } void test_construction_from_other_extents_with_invalid_values() { diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index 3d3d511a9e6..c48709d1875 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -90,10 +90,7 @@ constexpr void check_members(const extents& ext, index_se if constexpr (Ext::rank() > 0) { strides.front() = 1; for (size_t i = 1; i < Ext::rank(); ++i) { -#pragma warning(push) -#pragma warning(disable : 28020) // TRANSITION, DevCom-923103 strides[i] = static_cast(strides[i - 1] * ext.extent(i - 1)); -#pragma warning(pop) } } diff --git a/tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp index ae12da21424..b0b5f031e7d 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp @@ -59,7 +59,10 @@ void test_call_operator() { void test_stride_function() { layout_left::mapping> m; // Value of i must be less than extents_type::rank() +#pragma warning(push) +#pragma warning(disable : 28020) // yay, /analyze catches this mistake at compile time! (void) m.stride(1); +#pragma warning(pop) } int main(int argc, char* argv[]) { diff --git a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp index c16cff03661..ef08dd7e9a9 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp @@ -90,10 +90,7 @@ constexpr void check_members(const extents& ext, index_se if constexpr (Ext::rank() > 0) { strides.back() = 1; for (size_t i = Ext::rank() - 1; i-- > 0;) { -#pragma warning(push) -#pragma warning(disable : 28020) // TRANSITION, DevCom-923103 strides[i] = static_cast(strides[i + 1] * ext.extent(i + 1)); -#pragma warning(pop) } } diff --git a/tests/std/tests/P0009R18_mdspan_layout_right_death/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_right_death/test.cpp index 4e643353f18..ef72ed7be34 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_right_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_right_death/test.cpp @@ -59,7 +59,10 @@ void test_call_operator() { void test_stride_function() { layout_right::mapping> m; // Value of i must be less than extents_type::rank() +#pragma warning(push) +#pragma warning(disable : 28020) // yay, /analyze catches this mistake at compile time! (void) m.stride(1); +#pragma warning(pop) } int main(int argc, char* argv[]) { diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp index d276b22e7fb..5f34b8c1541 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp @@ -210,12 +210,9 @@ constexpr void do_check_members(const extents& ext, } { // Check 'stride' function - for (size_t i = 0; i < strs.size(); ++i) { + for (size_t i = 0; i < Ext::rank(); ++i) { same_as decltype(auto) s = m.stride(i); -#pragma warning(push) -#pragma warning(disable : 28020) // TRANSITION, DevCom-923103 assert(cmp_equal(strs[i], s)); -#pragma warning(pop) } } diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp index 3663f784d44..4668facbd22 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp @@ -61,7 +61,10 @@ void test_call_operator() { void test_stride_with_empty_extents() { layout_stride::mapping> m; // The argument to stride must be nonnegative and less than extents_type::rank() +#pragma warning(push) +#pragma warning(disable : 28020) // yay, /analyze catches this mistake at compile time! (void) m.stride(0); +#pragma warning(pop) } int main(int argc, char* argv[]) { diff --git a/tests/std/tests/P0024R2_parallel_algorithms_exclusive_scan/test.cpp b/tests/std/tests/P0024R2_parallel_algorithms_exclusive_scan/test.cpp index 5a00a8d07b9..36a08e7b56b 100644 --- a/tests/std/tests/P0024R2_parallel_algorithms_exclusive_scan/test.cpp +++ b/tests/std/tests/P0024R2_parallel_algorithms_exclusive_scan/test.cpp @@ -184,11 +184,6 @@ struct typesBop { bopResult operator()(intermediateType&&, intermediateType&&) { return 0; } - - // *result = binary_op(tmp, move(*result)) - bopResult operator()(intermediateType&, outputType&&) { - return 0; - } }; void test_case_exclusive_scan_init_writes_intermediate_type() { diff --git a/tests/std/tests/P0024R2_parallel_algorithms_inclusive_scan/test.cpp b/tests/std/tests/P0024R2_parallel_algorithms_inclusive_scan/test.cpp index a3ecee5b3bd..517a003a200 100644 --- a/tests/std/tests/P0024R2_parallel_algorithms_inclusive_scan/test.cpp +++ b/tests/std/tests/P0024R2_parallel_algorithms_inclusive_scan/test.cpp @@ -193,11 +193,6 @@ struct typesBop { bopResult operator()(intermediateType&&, intermediateType&&) { return 0; } - - // *result = binary_op(tmp, move(*result)) - bopResult operator()(intermediateType&, outputType&&) { - return 0; - } }; void test_case_inclusive_scan_init_writes_intermediate_type() { diff --git a/tests/std/tests/P0024R2_parallel_algorithms_transform_exclusive_scan/test.cpp b/tests/std/tests/P0024R2_parallel_algorithms_transform_exclusive_scan/test.cpp index 7cb3d6f11d6..12b8440dd48 100644 --- a/tests/std/tests/P0024R2_parallel_algorithms_transform_exclusive_scan/test.cpp +++ b/tests/std/tests/P0024R2_parallel_algorithms_transform_exclusive_scan/test.cpp @@ -179,11 +179,6 @@ struct typesBop { bopResult operator()(intermediateType&&, intermediateType&&) { return 0; } - - // *result = binary_op(tmp, move(*result)) - bopResult operator()(intermediateType&, outputType&&) { - return 0; - } }; void test_case_transform_exclusive_scan_init_writes_intermediate_type() { diff --git a/tests/std/tests/P0024R2_parallel_algorithms_transform_inclusive_scan/test.cpp b/tests/std/tests/P0024R2_parallel_algorithms_transform_inclusive_scan/test.cpp index c54e01aa69d..b1aa6eaec09 100644 --- a/tests/std/tests/P0024R2_parallel_algorithms_transform_inclusive_scan/test.cpp +++ b/tests/std/tests/P0024R2_parallel_algorithms_transform_inclusive_scan/test.cpp @@ -203,11 +203,6 @@ struct typesBop { bopResult operator()(intermediateType&&, intermediateType&&) { return 0; } - - // *result = binary_op(tmp, move(*result)) - bopResult operator()(intermediateType&, outputType&&) { - return 0; - } }; void test_case_transform_inclusive_scan_init_writes_intermediate_type() { diff --git a/tests/std/tests/P0218R1_filesystem/test.cpp b/tests/std/tests/P0218R1_filesystem/test.cpp index c7907450e42..c1c17d97412 100644 --- a/tests/std/tests/P0218R1_filesystem/test.cpp +++ b/tests/std/tests/P0218R1_filesystem/test.cpp @@ -3859,11 +3859,12 @@ basic_ostream& operator<<(basic_ostream& ostr, const L"symlink"sv, L"block"sv, L"character"sv, L"fifo"sv, L"socket"sv, L"unknown"sv, L"junction"sv}}; const size_t index = static_cast(ft); - if (!EXPECT(index < names.size())) { + if (index < names.size()) { + return ostr << L"file_type::" << names[index]; + } else { + EXPECT(false); return ostr << L"!!! INVALID file_type(" << index << L") !!!!"; } - - return ostr << L"file_type::" << names[index]; } template @@ -3950,7 +3951,7 @@ void test_devcom_953628() { // COMPILE-ONLY path{S{}}; } -int wmain(int argc, wchar_t* argv[]) { +int run_all_tests(int argc, wchar_t* argv[]) { error_code ec; // Store old path and change current path to a temporary path @@ -4077,4 +4078,20 @@ int wmain(int argc, wchar_t* argv[]) { EXPECT(good(ec)); assert(pass); + + return 0; +} + +int wmain(int argc, wchar_t* argv[]) { + try { + return run_all_tests(argc, argv); + } catch (const filesystem_error& fe) { + cout << "filesystem_error: " << fe.what() << endl; + } catch (const exception& e) { + cout << "exception: " << e.what() << endl; + } catch (...) { + cout << "Unknown exception." << endl; + } + + return EXIT_FAILURE; } diff --git a/tests/std/tests/P0323R12_expected/test.cpp b/tests/std/tests/P0323R12_expected/test.cpp index e5cc5cc35d2..1c97c0092c3 100644 --- a/tests/std/tests/P0323R12_expected/test.cpp +++ b/tests/std/tests/P0323R12_expected/test.cpp @@ -2343,6 +2343,53 @@ constexpr bool test_inherited_constructors() { static_assert(test_inherited_constructors()); +// Test GH-4279 "Add deleted function overloads to expected" + +template +struct ambiguating_expected_copy_constructor_caller { + struct const_lvalue_taker { + const_lvalue_taker(const expected&) {} + }; + + void operator()(expected) {} + void operator()(const_lvalue_taker) {} +}; + +template +struct ambiguating_expected_assignment_source { + operator const expected&() && { + return ex; + } + + operator expected&&() && { + return move(ex); + } + + expected ex; +}; + +struct move_only { + move_only() = default; + move_only(move_only&&) = default; + move_only& operator=(move_only&&) = default; +}; + +static_assert(is_invocable_v, const expected&>); +static_assert(is_invocable_v, const expected&>); +static_assert( + !is_invocable_v, const expected&>); +static_assert( + !is_invocable_v, const expected&>); + +#ifndef __EDG__ // TRANSITION, VSO-1601179 +static_assert(!is_assignable_v&, ambiguating_expected_assignment_source>); +static_assert(!is_assignable_v&, ambiguating_expected_assignment_source>); +#endif // ^^^ no workaround ^^^ +#ifndef __EDG__ // TRANSITION, VSO-2188364 +static_assert(!is_assignable_v&, ambiguating_expected_assignment_source>); +static_assert(!is_assignable_v&, ambiguating_expected_assignment_source>); +#endif // ^^^ no workaround ^^^ + int main() { test_unexpected::test_all(); static_assert(test_unexpected::test_all()); diff --git a/tests/std/tests/P0952R2_new_generate_canonical/test.cpp b/tests/std/tests/P0952R2_new_generate_canonical/test.cpp index 187d202a288..527faf8aee1 100644 --- a/tests/std/tests/P0952R2_new_generate_canonical/test.cpp +++ b/tests/std/tests/P0952R2_new_generate_canonical/test.cpp @@ -128,7 +128,7 @@ int main() { const auto expected3 = ldexpf(0xDE'55'2C >> (3 * 8 - 24), -24); assert((generate_with_ibe) () == expected1); - assert((generate_with_ibe) () == expected2); // needs a 64 bit accumulator for $S$ + assert((generate_with_ibe) () == expected2); assert((generate_with_ibe) () == expected3); } @@ -149,7 +149,7 @@ int main() { assert((generate_with_ibe) () == expected1); assert((generate_with_ibe) () == expected2); - assert((generate_with_ibe) () == expected3); // needs a 128 bit accumulator for $S$ + assert((generate_with_ibe) () == expected3); } { diff --git a/tests/std/tests/P1135R6_atomic_wait_win7/env.lst b/tests/std/tests/P1135R6_atomic_wait_win7/env.lst new file mode 100644 index 00000000000..351a8293d9d --- /dev/null +++ b/tests/std/tests/P1135R6_atomic_wait_win7/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_20_matrix.lst diff --git a/tests/std/tests/P1135R6_atomic_wait_win7/test.cpp b/tests/std/tests/P1135R6_atomic_wait_win7/test.cpp new file mode 100644 index 00000000000..d6deabafaaf --- /dev/null +++ b/tests/std/tests/P1135R6_atomic_wait_win7/test.cpp @@ -0,0 +1,371 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +template