diff --git a/.github/workflows/update-status-chart.yml b/.github/workflows/update-status-chart.yml index 37e7f5db180..ec42d63e72d 100644 --- a/.github/workflows/update-status-chart.yml +++ b/.github/workflows/update-status-chart.yml @@ -18,7 +18,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v3 with: - node-version: ">=17.8.0" + node-version: ">=20.4.0" - name: Install Packages run: | npm ci diff --git a/README.md b/README.md index a4f9f458025..4f699bd9660 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ 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.7 Preview 2 or later. +1. Install Visual Studio 2022 17.7 Preview 3 or later. * Select "Windows 11 SDK (10.0.22000.0)" in the VS Installer. * 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. @@ -157,7 +157,7 @@ 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.7 Preview 2 or later. +1. Install Visual Studio 2022 17.7 Preview 3 or later. * Select "Windows 11 SDK (10.0.22000.0)" in the VS Installer. * 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. diff --git a/azure-devops/create-1es-hosted-pool.ps1 b/azure-devops/create-1es-hosted-pool.ps1 index a8afa4759a5..232464f305f 100644 --- a/azure-devops/create-1es-hosted-pool.ps1 +++ b/azure-devops/create-1es-hosted-pool.ps1 @@ -14,7 +14,7 @@ $ErrorActionPreference = 'Stop' $CurrentDate = Get-Date $Location = 'eastus' -$VMSize = 'Standard_D32ads_v5' +$VMSize = 'Standard_D32ds_v5' $ProtoVMName = 'PROTOTYPE' $ImagePublisher = 'MicrosoftWindowsServer' $ImageOffer = 'WindowsServer' diff --git a/azure-devops/provision-image.ps1 b/azure-devops/provision-image.ps1 index b97754cd955..d87f5b47491 100644 --- a/azure-devops/provision-image.ps1 +++ b/azure-devops/provision-image.ps1 @@ -91,7 +91,7 @@ if ([string]::IsNullOrEmpty($AdminUserPassword)) { $PsExecPath = Join-Path $ExtractedPsToolsPath 'PsExec64.exe' # https://github.com/PowerShell/PowerShell/releases/latest - $PowerShellZipUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/PowerShell-7.3.4-win-x64.zip' + $PowerShellZipUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.3.5/PowerShell-7.3.5-win-x64.zip' Write-Host "Downloading: $PowerShellZipUrl" $ExtractedPowerShellPath = DownloadAndExtractZip -Url $PowerShellZipUrl $PwshPath = Join-Path $ExtractedPowerShellPath 'pwsh.exe' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 124da209a6f..4c306b0c311 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: benchmarkBuildOutputLocation: 'D:\benchmark' pool: - name: 'StlBuild-2023-06-13T1913-Pool' + name: 'StlBuild-2023-07-11T1513-Pool' demands: EnableSpotVM -equals true pr: diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index cc188710c1c..11df4398d00 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -105,6 +105,8 @@ function(add_benchmark name) target_compile_definitions(benchmark-${name} PRIVATE BENCHMARK_STATIC_DEFINE) endfunction() +add_benchmark(bitset_to_string src/bitset_to_string.cpp) add_benchmark(locale_classic src/locale_classic.cpp) +add_benchmark(path_lexically_normal src/path_lexically_normal.cpp) add_benchmark(random_integer_generation src/random_integer_generation.cpp) add_benchmark(std_copy src/std_copy.cpp) diff --git a/benchmarks/src/bitset_to_string.cpp b/benchmarks/src/bitset_to_string.cpp new file mode 100644 index 00000000000..8e219a269d1 --- /dev/null +++ b/benchmarks/src/bitset_to_string.cpp @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace { + const auto random_bits = [] { + mt19937_64 rnd{}; + array arr; + for (auto& d : arr) { + d = rnd(); + } + return arr; + }(); + + template + void BM_bitset_to_string(benchmark::State& state) { + for (auto _ : state) { + for (const auto& bits : random_bits) { + bitset bs{bits}; + benchmark::DoNotOptimize(bs.to_string()); + } + } + } + + template + void BM_bitset_to_string_large_single(benchmark::State& state) { + const auto large_bitset = bit_cast>(random_bits); + for (auto _ : state) { + benchmark::DoNotOptimize(large_bitset.to_string()); + } + } +} // namespace + +BENCHMARK(BM_bitset_to_string<15, char>); +BENCHMARK(BM_bitset_to_string<64, char>); +BENCHMARK(BM_bitset_to_string_large_single); +BENCHMARK(BM_bitset_to_string<7, wchar_t>); +BENCHMARK(BM_bitset_to_string<64, wchar_t>); +BENCHMARK(BM_bitset_to_string_large_single); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/path_lexically_normal.cpp b/benchmarks/src/path_lexically_normal.cpp new file mode 100644 index 00000000000..48c842de319 --- /dev/null +++ b/benchmarks/src/path_lexically_normal.cpp @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +namespace { + void BM_lexically_normal(benchmark::State& state) { + using namespace std::literals; + static constexpr std::wstring_view args[5]{ + LR"(X:DriveRelative)"sv, + LR"(\\server\\\share)"sv, + LR"(STL/.github/workflows/../..)"sv, + LR"(C:\Program Files\Azure Data Studio\resources\app\extensions\bat\snippets\batchfile.code-snippets)"sv, + LR"(/\server/\share/\a/\b/\c/\./\./\d/\../\../\../\../\../\../\../\other/x/y/z/.././..\meow.txt)"sv, + }; + + const auto index = state.range(0); + const std::filesystem::path p(args[index]); + for (auto _ : state) { + benchmark::DoNotOptimize(p.lexically_normal()); + } + } +} // namespace + +BENCHMARK(BM_lexically_normal)->DenseRange(0, 4, 1); + +BENCHMARK_MAIN(); diff --git a/stl/inc/__msvc_bit_utils.hpp b/stl/inc/__msvc_bit_utils.hpp index 04f45b03f29..89d5d4c1947 100644 --- a/stl/inc/__msvc_bit_utils.hpp +++ b/stl/inc/__msvc_bit_utils.hpp @@ -49,19 +49,19 @@ _INLINE_VAR constexpr int _Unsigned_integer_digits = sizeof(_UInt) * CHAR_BIT; // see "Hacker's Delight" section 5-3 template _NODISCARD constexpr int _Countl_zero_fallback(_Ty _Val) noexcept { - _Ty _Yy = 0; + _Ty _Yx = 0; - unsigned int _Nn = _Unsigned_integer_digits<_Ty>; - unsigned int _Cc = _Unsigned_integer_digits<_Ty> / 2; + unsigned int _Nx = _Unsigned_integer_digits<_Ty>; + unsigned int _Cx = _Unsigned_integer_digits<_Ty> / 2; do { - _Yy = static_cast<_Ty>(_Val >> _Cc); - if (_Yy != 0) { - _Nn -= _Cc; - _Val = _Yy; + _Yx = static_cast<_Ty>(_Val >> _Cx); + if (_Yx != 0) { + _Nx -= _Cx; + _Val = _Yx; } - _Cc >>= 1; - } while (_Cc != 0); - return static_cast(_Nn) - static_cast(_Val); + _Cx >>= 1; + } while (_Cx != 0); + return static_cast(_Nx) - static_cast(_Val); } #if !defined(_M_CEE_PURE) && !defined(__CUDACC__) && !defined(__INTEL_COMPILER) diff --git a/stl/inc/__msvc_chrono.hpp b/stl/inc/__msvc_chrono.hpp index 45b9f75f782..581d2e74f0d 100644 --- a/stl/inc/__msvc_chrono.hpp +++ b/stl/inc/__msvc_chrono.hpp @@ -666,18 +666,37 @@ namespace chrono { using time_point = _CHRONO time_point; static constexpr bool is_steady = true; +#if defined(_M_ARM) || defined(_M_ARM64) // vvv ARM or ARM64 arch vvv +#define _LIKELY_ARM_ARM64 _LIKELY +#define _LIKELY_X86_X64 +#elif defined(_M_IX86) || defined(_M_X64) // ^^^ ARM or ARM64 arch / x86 or x64 arch vvv +#define _LIKELY_ARM_ARM64 +#define _LIKELY_X86_X64 _LIKELY +#else // ^^^ x86 or x64 arch / other arch vvv +#define _LIKELY_ARM_ARM64 +#define _LIKELY_X86_X64 +#endif // ^^^ other arch ^^^ _NODISCARD static time_point now() noexcept { // get current time const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot const long long _Ctr = _Query_perf_counter(); static_assert(period::num == 1, "This assumes period::num == 1."); - // 10 MHz is a very common QPC frequency on modern PCs. Optimizing for - // this specific frequency can double the performance of this function by - // avoiding the expensive frequency conversion path. - constexpr long long _TenMHz = 10'000'000; - if (_Freq == _TenMHz) { + // The compiler recognizes the constants for frequency and time period and uses shifts and + // multiplies instead of divides to calculate the nanosecond value. + constexpr long long _TenMHz = 10'000'000; + constexpr long long _TwentyFourMHz = 24'000'000; + // clang-format off + if (_Freq == _TenMHz) _LIKELY_X86_X64 { + // 10 MHz is a very common QPC frequency on modern x86/x64 PCs. Optimizing for + // this specific frequency can double the performance of this function by + // avoiding the expensive frequency conversion path. static_assert(period::den % _TenMHz == 0, "It should never fail."); constexpr long long _Multiplier = period::den / _TenMHz; return time_point(duration(_Ctr * _Multiplier)); + } else if (_Freq == _TwentyFourMHz) _LIKELY_ARM_ARM64 { + // 24 MHz is a common frequency on ARM/ARM64, including cases where it emulates x86/x64. + const long long _Whole = (_Ctr / _TwentyFourMHz) * period::den; + const long long _Part = (_Ctr % _TwentyFourMHz) * period::den / _TwentyFourMHz; + return time_point(duration(_Whole + _Part)); } else { // Instead of just having "(_Ctr * period::den) / _Freq", // the algorithm below prevents overflow when _Ctr is sufficiently large. @@ -688,7 +707,10 @@ namespace chrono { const long long _Part = (_Ctr % _Freq) * period::den / _Freq; return time_point(duration(_Whole + _Part)); } + // clang-format on } +#undef _LIKELY_ARM_ARM64 +#undef _LIKELY_X86_X64 }; _EXPORT_STD using high_resolution_clock = steady_clock; diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 61ea8e29b16..31be4971b84 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -43,17 +43,14 @@ _STD_BEGIN #if defined(_M_X64) && !defined(_M_ARM64EC) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) \ && !defined(__INTEL_COMPILER) #define _STL_128_INTRINSICS 1 -#ifdef __clang__ -#define _STL_128_ADD_SUB_INTRINSICS 0 // clang doesn't have _addcarry_u64 / _subborrow_u64 -#define _STL_128_DIV_INTRINSICS 0 // clang doesn't have _udiv128 / _div128 -#else // ^^^ Clang / other compilers vvv -#define _STL_128_ADD_SUB_INTRINSICS 1 -#define _STL_128_DIV_INTRINSICS 1 -#endif // ^^^ other compilers ^^^ +#ifdef __clang__ // clang doesn't have _udiv128 / _div128 +#define _STL_128_DIV_INTRINSICS 0 +#else // ^^^ Clang / other vvv +#define _STL_128_DIV_INTRINSICS 1 +#endif // ^^^ detect _udiv128 / _div128 ^^^ #else // ^^^ intrinsics available / intrinsics unavailable vvv -#define _STL_128_INTRINSICS 0 -#define _STL_128_ADD_SUB_INTRINSICS 0 -#define _STL_128_DIV_INTRINSICS 0 +#define _STL_128_INTRINSICS 0 +#define _STL_128_DIV_INTRINSICS 0 #endif // ^^^ intrinsics unavailable ^^^ template @@ -132,11 +129,11 @@ struct static constexpr unsigned char _AddCarry64( unsigned char _Carry, uint64_t _Left, uint64_t _Right, uint64_t& _Result) noexcept { // _STL_INTERNAL_CHECK(_Carry < 2); -#if _STL_128_ADD_SUB_INTRINSICS +#if _STL_128_INTRINSICS if (!_Is_constant_evaluated()) { return _addcarry_u64(_Carry, _Left, _Right, &_Result); } -#endif // _STL_128_ADD_SUB_INTRINSICS +#endif // _STL_128_INTRINSICS const uint64_t _Sum = _Left + _Right + _Carry; _Result = _Sum; @@ -146,11 +143,11 @@ struct static constexpr unsigned char _SubBorrow64( unsigned char _Carry, uint64_t _Left, uint64_t _Right, uint64_t& _Result) noexcept { // _STL_INTERNAL_CHECK(_Carry < 2); -#if _STL_128_ADD_SUB_INTRINSICS +#if _STL_128_INTRINSICS if (!_Is_constant_evaluated()) { return _subborrow_u64(_Carry, _Left, _Right, &_Result); } -#endif // _STL_128_ADD_SUB_INTRINSICS +#endif // _STL_128_INTRINSICS const auto _Difference = _Left - _Right - _Carry; _Result = _Difference; diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 7a8f91dc1aa..466fbf25731 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -21,6 +21,12 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new +// TRANSITION, non-_Ugly attribute tokens +#pragma push_macro("msvc") +#pragma push_macro("lifetimebound") +#undef msvc +#undef lifetimebound + #if _USE_STD_VECTOR_ALGORITHMS _EXTERN_C @@ -10003,8 +10009,9 @@ namespace ranges { #endif // _HAS_CXX17 _EXPORT_STD template -_NODISCARD constexpr pair minmax(const _Ty& _Left, const _Ty& _Right, _Pr _Pred) noexcept( - noexcept(_DEBUG_LT_PRED(_Pred, _Right, _Left))) /* strengthened */ { +_NODISCARD constexpr pair minmax(const _Ty& _Left _MSVC_LIFETIMEBOUND, + const _Ty& _Right _MSVC_LIFETIMEBOUND, + _Pr _Pred) noexcept(noexcept(_DEBUG_LT_PRED(_Pred, _Right, _Left))) /* strengthened */ { // return pair(leftmost/smaller, rightmost/larger) of _Left and _Right if (_DEBUG_LT_PRED(_Pred, _Right, _Left)) { return {_Right, _Left}; @@ -10021,8 +10028,8 @@ _NODISCARD constexpr pair<_Ty, _Ty> minmax(initializer_list<_Ty> _Ilist, _Pr _Pr } _EXPORT_STD template -_NODISCARD constexpr pair minmax(const _Ty& _Left, const _Ty& _Right) noexcept( - noexcept(_Right < _Left)) /* strengthened */ { +_NODISCARD constexpr pair minmax(const _Ty& _Left _MSVC_LIFETIMEBOUND, + const _Ty& _Right _MSVC_LIFETIMEBOUND) noexcept(noexcept(_Right < _Left)) /* strengthened */ { // return pair(leftmost/smaller, rightmost/larger) of _Left and _Right if (_Right < _Left) { _STL_ASSERT(!(_Left < _Right), "invalid comparator"); @@ -10049,8 +10056,8 @@ namespace ranges { template > _Pr = ranges::less> - _NODISCARD constexpr minmax_result operator()( - const _Ty& _Left, const _Ty& _Right, _Pr _Pred = {}, _Pj _Proj = {}) const { + _NODISCARD constexpr minmax_result operator()(const _Ty& _Left _MSVC_LIFETIMEBOUND, + const _Ty& _Right _MSVC_LIFETIMEBOUND, _Pr _Pred = {}, _Pj _Proj = {}) const { if (_STD invoke(_Pred, _STD invoke(_Proj, _Right), _STD invoke(_Proj, _Left))) { return {_Right, _Left}; } else { @@ -10673,6 +10680,11 @@ namespace ranges { #endif // _HAS_CXX17 _STD_END + +// TRANSITION, non-_Ugly attribute tokens +#pragma pop_macro("lifetimebound") +#pragma pop_macro("msvc") + #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) diff --git a/stl/inc/array b/stl/inc/array index 53de2fd7f55..026e04268b6 100644 --- a/stl/inc/array +++ b/stl/inc/array @@ -761,7 +761,7 @@ public: conditional_t, _Is_implicitly_default_constructible<_Ty>>, _Ty, _Empty_array_element> - _Elems[1]; + _Elems[1]{}; private: [[noreturn]] static void _Xran() { diff --git a/stl/inc/bitset b/stl/inc/bitset index 488c57eb2a6..b91f8a6eb38 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -22,12 +22,13 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN _EXPORT_STD template class bitset { // store fixed-length sequence of Boolean elements -public: +private: #pragma warning(push) #pragma warning(disable : 4296) // expression is always true (/Wall) using _Ty = conditional_t<_Bits <= sizeof(unsigned long) * CHAR_BIT, unsigned long, unsigned long long>; #pragma warning(pop) +public: class reference { // proxy for an element friend bitset; @@ -68,7 +69,8 @@ public: size_t _Mypos; // position of element in bitset }; - static _CONSTEXPR23 void _Validate(const size_t _Pos) noexcept { // verify that _Pos is within bounds +private: + static constexpr void _Validate(const size_t _Pos) noexcept { // verify that _Pos is within bounds #if _ITERATOR_DEBUG_LEVEL == 0 (void) _Pos; #else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 / _ITERATOR_DEBUG_LEVEL != 0 vvv @@ -76,17 +78,17 @@ public: #endif // _ITERATOR_DEBUG_LEVEL == 0 } - constexpr bool _Subscript(size_t _Pos) const { + constexpr bool _Subscript(size_t _Pos) const noexcept { return (_Array[_Pos / _Bitsperword] & (_Ty{1} << _Pos % _Bitsperword)) != 0; } - _NODISCARD constexpr bool operator[](size_t _Pos) const { -#if _ITERATOR_DEBUG_LEVEL == 0 - return _Subscript(_Pos); + static constexpr bool _Need_mask = _Bits < CHAR_BIT * sizeof(unsigned long long); + static constexpr unsigned long long _Mask = (1ULL << (_Need_mask ? _Bits : 0)) - 1ULL; -#else // _ITERATOR_DEBUG_LEVEL == 0 - return _Bits <= _Pos ? (_Validate(_Pos), false) : _Subscript(_Pos); -#endif // _ITERATOR_DEBUG_LEVEL == 0 +public: + _NODISCARD constexpr bool operator[](size_t _Pos) const noexcept /* strengthened */ { + _Validate(_Pos); + return _Subscript(_Pos); } _NODISCARD _CONSTEXPR23 reference operator[](const size_t _Pos) noexcept /* strengthened */ { @@ -96,12 +98,9 @@ public: constexpr bitset() noexcept : _Array() {} // construct with all false values - static constexpr bool _Need_mask = _Bits < CHAR_BIT * sizeof(unsigned long long); - - static constexpr unsigned long long _Mask = (1ULL << (_Need_mask ? _Bits : 0)) - 1ULL; - constexpr bitset(unsigned long long _Val) noexcept : _Array{static_cast<_Ty>(_Need_mask ? _Val & _Mask : _Val)} {} +private: template _CONSTEXPR23 void _Construct(const _Elem* const _Ptr, size_t _Count, const _Elem _Elem0, const _Elem _Elem1) { if (_Count > _Bits) { @@ -147,6 +146,7 @@ public: } } +public: template _CONSTEXPR23 explicit bitset(const basic_string<_Elem, _Traits, _Alloc>& _Str, typename basic_string<_Elem, _Traits, _Alloc>::size_type _Pos = 0, @@ -347,11 +347,11 @@ public: _NODISCARD _CONSTEXPR23 basic_string<_Elem, _Tr, _Alloc> to_string( const _Elem _Elem0 = static_cast<_Elem>('0'), const _Elem _Elem1 = static_cast<_Elem>('1')) const { // convert bitset to string - basic_string<_Elem, _Tr, _Alloc> _Str; - _Str.reserve(_Bits); - - for (auto _Pos = _Bits; 0 < _Pos;) { - _Str.push_back(_Subscript(--_Pos) ? _Elem1 : _Elem0); + basic_string<_Elem, _Tr, _Alloc> _Str(_Bits, _Elem0); + for (size_t _Pos = 0; _Pos < _Bits; ++_Pos) { + if (_Subscript(_Bits - 1 - _Pos)) { + _Str[_Pos] = _Elem1; + } } return _Str; diff --git a/stl/inc/complex b/stl/inc/complex index c95ed2d8b2c..ce60701b764 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -1531,8 +1531,8 @@ _NODISCARD _Ty abs(const complex<_Ty>& _Left) { _EXPORT_STD template _NODISCARD complex<_Ty> acos(const complex<_Ty>& _Left) { - const _Ty _Arcbig = static_cast<_Ty>(0.25) * _Ctraits<_Ty>::sqrt(_Ctraits<_Ty>::_Flt_max()); - constexpr _Ty _Pi = static_cast<_Ty>(3.1415926535897932384626433832795029L); + const _Ty _Arcbig = static_cast<_Ty>(0.25) * _Ctraits<_Ty>::sqrt(_Ctraits<_Ty>::_Flt_max()); + constexpr _Ty _Pi_val = static_cast<_Ty>(3.1415926535897932384626433832795029L); const _Ty _Re = real(_Left); const _Ty _Im = imag(_Left); @@ -1545,18 +1545,18 @@ _NODISCARD complex<_Ty> acos(const complex<_Ty>& _Left) { } else if (_Ctraits<_Ty>::_Isinf(_Re)) { // (+/-Inf, not NaN) if (_Ctraits<_Ty>::_Isinf(_Im)) { if (_Re < 0) { - _Ux = static_cast<_Ty>(0.75) * _Pi; // (-Inf, +/-Inf) + _Ux = static_cast<_Ty>(0.75) * _Pi_val; // (-Inf, +/-Inf) } else { - _Ux = static_cast<_Ty>(0.25) * _Pi; // (+Inf, +/-Inf) + _Ux = static_cast<_Ty>(0.25) * _Pi_val; // (+Inf, +/-Inf) } } else if (_Re < 0) { - _Ux = _Pi; // (-Inf, finite) + _Ux = _Pi_val; // (-Inf, finite) } else { _Ux = 0; // (+Inf, finite) } _Vx = -_Ctraits<_Ty>::_Copysign(_Ctraits<_Ty>::_Infv(), _Im); } else if (_Ctraits<_Ty>::_Isinf(_Im)) { // (finite, finite) - _Ux = static_cast<_Ty>(0.50) * _Pi; // (finite, +/-Inf) + _Ux = static_cast<_Ty>(0.50) * _Pi_val; // (finite, +/-Inf) _Vx = -_Im; } else { // (finite, finite) const complex<_Ty> _Wx = sqrt(complex<_Ty>(1 + _Re, -_Im)); @@ -1598,8 +1598,8 @@ _NODISCARD complex<_Ty> acos(const complex<_Ty>& _Left) { _EXPORT_STD template _NODISCARD complex<_Ty> acosh(const complex<_Ty>& _Left) { - const _Ty _Arcbig = static_cast<_Ty>(0.25) * _Ctraits<_Ty>::sqrt(_Ctraits<_Ty>::_Flt_max()); - constexpr _Ty _Pi = static_cast<_Ty>(3.1415926535897932384626433832795029L); + const _Ty _Arcbig = static_cast<_Ty>(0.25) * _Ctraits<_Ty>::sqrt(_Ctraits<_Ty>::_Flt_max()); + constexpr _Ty _Pi_val = static_cast<_Ty>(3.1415926535897932384626433832795029L); const _Ty _Re = real(_Left); _Ty _Im = imag(_Left); @@ -1614,12 +1614,12 @@ _NODISCARD complex<_Ty> acosh(const complex<_Ty>& _Left) { if (_Ctraits<_Ty>::_Isinf(_Im)) { if (_Re < 0) { - _Vx = static_cast<_Ty>(0.75) * _Pi; // (-Inf, +/-Inf) + _Vx = static_cast<_Ty>(0.75) * _Pi_val; // (-Inf, +/-Inf) } else { - _Vx = static_cast<_Ty>(0.25) * _Pi; // (+Inf, +/-Inf) + _Vx = static_cast<_Ty>(0.25) * _Pi_val; // (+Inf, +/-Inf) } } else if (_Re < 0) { - _Vx = _Pi; // (-Inf, finite) + _Vx = _Pi_val; // (-Inf, finite) } else { _Vx = 0; // (+Inf, finite) } @@ -1627,7 +1627,7 @@ _NODISCARD complex<_Ty> acosh(const complex<_Ty>& _Left) { _Vx = _Ctraits<_Ty>::_Copysign(_Vx, _Im); } else if (_Ctraits<_Ty>::_Isinf(_Im)) { // (finite, +/-Inf) _Ux = _Ctraits<_Ty>::_Infv(); - _Vx = _Ctraits<_Ty>::_Copysign(static_cast<_Ty>(0.50) * _Pi, _Im); + _Vx = _Ctraits<_Ty>::_Copysign(static_cast<_Ty>(0.50) * _Pi_val, _Im); } else { // (finite, finite) const complex<_Ty> _Wx = sqrt(complex<_Ty>(_Re - 1, -_Im)); const complex<_Ty> _Zx = sqrt(complex<_Ty>(_Re + 1, _Im)); @@ -1668,8 +1668,8 @@ _NODISCARD complex<_Ty> acosh(const complex<_Ty>& _Left) { _EXPORT_STD template _NODISCARD complex<_Ty> asinh(const complex<_Ty>& _Left) { - const _Ty _Arcbig = static_cast<_Ty>(0.25) * _Ctraits<_Ty>::sqrt(_Ctraits<_Ty>::_Flt_max()); - constexpr _Ty _Pi = static_cast<_Ty>(3.1415926535897932384626433832795029L); + const _Ty _Arcbig = static_cast<_Ty>(0.25) * _Ctraits<_Ty>::sqrt(_Ctraits<_Ty>::_Flt_max()); + constexpr _Ty _Pi_val = static_cast<_Ty>(3.1415926535897932384626433832795029L); const _Ty _Re = real(_Left); _Ty _Im = imag(_Left); @@ -1684,14 +1684,14 @@ _NODISCARD complex<_Ty> asinh(const complex<_Ty>& _Left) { if (_Ctraits<_Ty>::_Isinf(_Im)) { // (+/-Inf, +/-Inf) _Ux = _Re; - _Vx = _Ctraits<_Ty>::_Copysign(static_cast<_Ty>(0.25) * _Pi, _Im); + _Vx = _Ctraits<_Ty>::_Copysign(static_cast<_Ty>(0.25) * _Pi_val, _Im); } else { // (+/-Inf, finite) _Ux = _Re; _Vx = _Ctraits<_Ty>::_Copysign(_Ty{0}, _Im); } } else if (_Ctraits<_Ty>::_Isinf(_Im)) { // (finite, +/-Inf) _Ux = _Ctraits<_Ty>::_Copysign(_Ctraits<_Ty>::_Infv(), _Re); - _Vx = _Ctraits<_Ty>::_Copysign(static_cast<_Ty>(0.50) * _Pi, _Im); + _Vx = _Ctraits<_Ty>::_Copysign(static_cast<_Ty>(0.50) * _Pi_val, _Im); } else { // (finite, finite) const complex<_Ty> _Wx = sqrt(complex<_Ty>(1 - _Im, _Re)); const complex<_Ty> _Zx = sqrt(complex<_Ty>(1 + _Im, -_Re)); @@ -2037,7 +2037,7 @@ _NODISCARD complex<_Ty> tanh(const complex<_Ty>& _Left) { _Real = _Ty{1}; } - return complex<_Ty>(_Real, _Tv* _Ty{0}); + return complex<_Ty>(_Real, _Tv * _Ty{0}); } return complex<_Ty>((_Ctraits<_Ty>::sqrt(_Ty{1} + _Sv * _Sv)) * _Bv / _Dv, _Tv / _Dv); diff --git a/stl/inc/deque b/stl/inc/deque index 2eb29ec475d..9eb2cfd6f44 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -1316,7 +1316,7 @@ private: } }; - enum class _Is_bidi : bool { _No, _Yes }; + enum class _Is_bidi : bool { _Nope, _Yes }; template <_Is_bidi _Bidi, class _Iter, class _Sent> iterator _Insert_range(const size_type _Off, _Iter _First, _Sent _Last) { @@ -1352,7 +1352,7 @@ private: const auto _Num = static_cast(_Mysize() - _Oldsize); const auto _Myfirst = _Unchecked_begin(); const auto _Mymid = _Myfirst + _Num; - if constexpr (_Bidi == _Is_bidi::_No) { + if constexpr (_Bidi == _Is_bidi::_Nope) { _STD reverse(_Myfirst, _Mymid); // flip new stuff in place } _STD rotate(_Myfirst, _Mymid, _Mymid + static_cast(_Off)); @@ -1392,7 +1392,7 @@ public: return _Insert_range<_Is_bidi::_Yes>( _Off, _RANGES _Ubegin(_Range), _RANGES _Get_final_iterator_unwrapped(_Range)); } else { - return _Insert_range<_Is_bidi::_No>(_Off, _RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + return _Insert_range<_Is_bidi::_Nope>(_Off, _RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); } } #endif // _HAS_CXX23 && defined(__cpp_lib_concepts) diff --git a/stl/inc/expected b/stl/inc/expected index 4156fbf52db..ce22ebf67ed 100644 --- a/stl/inc/expected +++ b/stl/inc/expected @@ -1423,7 +1423,6 @@ public: } } constexpr void value() && { - // per LWG-3940 // TRANSITION, DevCom-1638273 and LLVM-53224 static_assert(is_copy_constructible_v<_Err>, "is_copy_constructible_v must be true"); static_assert(is_move_constructible_v<_Err>, "is_move_constructible_v must be true"); diff --git a/stl/inc/filesystem b/stl/inc/filesystem index 30a92a9a82e..737d632f4fa 100644 --- a/stl/inc/filesystem +++ b/stl/inc/filesystem @@ -16,7 +16,6 @@ _EMIT_STL_WARNING(STL4038, "The contents of are available only with #include #include #include -#include #include #include #include @@ -619,7 +618,7 @@ namespace filesystem { friend inline __std_win_error _Absolute(path& _Result, const wstring& _Text); friend inline __std_win_error _Canonical(path& _Result, const wstring& _Text); friend inline path temp_directory_path(error_code& _Ec); - friend inline __std_win_error _Current_path(path& _Result) noexcept; + friend inline path current_path(error_code& _Ec); friend inline void current_path(const path& _To); friend inline void current_path(const path& _To, error_code& _Ec) noexcept; friend inline __std_win_error _Read_symlink(const path& _Symlink_path, path& _Result) noexcept; @@ -1204,80 +1203,91 @@ namespace filesystem { _STD replace(_Normalized.begin(), _Normalized.end(), L'/', L'\\'); // "3. Replace each directory-separator with a preferred-separator. - // [ Note: The generic pathname grammar (29.11.7.1) defines directory-separator + // [ Note 4: The generic pathname grammar defines directory-separator // as one or more slashes and preferred-separators. -end note ]" - list _Lst; // Empty wstring_view means directory-separator - // that will be normalized to a preferred-separator. - // Non-empty wstring_view means filename. - for (auto _Next = _Root_name_end; _Next != _Last;) { - if (_Is_slash(*_Next)) { - if (_Lst.empty() || !_Lst.back().empty()) { - // collapse one or more slashes and preferred-separators to one empty wstring_view - _Lst.emplace_back(); - } - - ++_Next; - } else { - const auto _Filename_end = _STD find_if(_Next + 1, _Last, _Is_slash); - _Lst.emplace_back(_Next, static_cast(_Filename_end - _Next)); - _Next = _Filename_end; + vector _Vec; // Empty wstring_view means directory-separator + // that will be normalized to a preferred-separator. + // Non-empty wstring_view means filename. + _Vec.reserve(13); // avoid frequent re-allocations + bool _Has_root_directory = false; // true: there is a slash right after root-name. + auto _Ptr = _Root_name_end; + if (_Ptr != _Last && _Is_slash(*_Ptr)) { + _Has_root_directory = true; + _Normalized += preferred_separator; + ++_Ptr; + while (_Ptr != _Last && _Is_slash(*_Ptr)) { + ++_Ptr; } } - - // "4. Remove each dot filename and any immediately following directory-separator." - for (auto _Next = _Lst.begin(); _Next != _Lst.end();) { - if (*_Next == _Dot) { - _Next = _Lst.erase(_Next); // erase dot filename - - if (_Next != _Lst.end()) { - _Next = _Lst.erase(_Next); // erase immediately following directory-separator + // _Vec will start with a filename (if not empty). + while (_Ptr != _Last) { + if (_Is_slash(*_Ptr)) { + if (_Vec.empty() || !_Vec.back().empty()) { + // collapse one or more slashes and preferred-separators to one empty wstring_view + _Vec.emplace_back(); } + ++_Ptr; } else { - ++_Next; + const auto _Filename_end = _STD find_if(_Ptr + 1, _Last, _Is_slash); + _Vec.emplace_back(_Ptr, static_cast(_Filename_end - _Ptr)); + _Ptr = _Filename_end; } } + // "4. Remove each dot filename and any immediately following directory-separator." // "5. As long as any appear, remove a non-dot-dot filename immediately followed by a // directory-separator and a dot-dot filename, along with any immediately following directory-separator." - for (auto _Next = _Lst.begin(); _Next != _Lst.end();) { - auto _Prev = _Next; - - ++_Next; // If we aren't going to erase, keep advancing. - // If we're going to erase, _Next now points past the dot-dot filename. - - if (*_Prev == _Dot_dot && _Prev != _Lst.begin() && --_Prev != _Lst.begin() && *--_Prev != _Dot_dot) { - if (_Next != _Lst.end()) { // dot-dot filename has an immediately following directory-separator - ++_Next; - } - - _Lst.erase(_Prev, _Next); // _Next remains valid - } - } - // "6. If there is a root-directory, remove all dot-dot filenames // and any directory-separators immediately following them. - // [ Note: These dot-dot filenames attempt to refer to nonexistent parent directories. -end note ]" - if (!_Lst.empty() && _Lst.front().empty()) { // we have a root-directory - for (auto _Next = _Lst.begin(); _Next != _Lst.end();) { - if (*_Next == _Dot_dot) { - _Next = _Lst.erase(_Next); // erase dot-dot filename - - if (_Next != _Lst.end()) { - _Next = _Lst.erase(_Next); // erase immediately following directory-separator + // [ Note 5: These dot-dot filenames attempt to refer to nonexistent parent directories. -end note ]" + auto _New_end = _Vec.begin(); + for (auto _Pos = _Vec.begin(); _Pos != _Vec.end();) { + const auto _Elem = *_Pos++; // _Pos points at a filename here; it points at end or a separator after ++. + if (_Elem == _Dot) { + // ignore dot (and following separator). + if (_Pos == _Vec.end()) { + break; + } + } else if (_Elem != _Dot_dot) { + // append normal filename and separator. + *_New_end++ = _Elem; // _New_end points at end or a separator after ++. + if (_Pos == _Vec.end()) { + break; + } + ++_New_end; // _New_end(<=_Pos) doesn't point at end; accept separator. + } else { // _Dot_dot + if (_New_end != _Vec.begin() && _New_end[-2] != _Dot_dot) { + // _New_end == _Vec.begin() + 2n here. + // remove preceding non-dot-dot filename and separator. + _New_end -= 2; + if (_Pos == _Vec.end()) { + break; } + } else if (!_Has_root_directory) { + // due to 6, append dot-dot and separator only if !_Has_root_directory. + *_New_end++ = _Dot_dot; + if (_Pos == _Vec.end()) { + break; + } + ++_New_end; } else { - ++_Next; + // ignore dot-dot and separator. + if (_Pos == _Vec.end()) { + break; + } } } + ++_Pos; // _Pos points at a separator here; it points at end or a filename after ++. } + _Vec.erase(_New_end, _Vec.end()); // "7. If the last filename is dot-dot, remove any trailing directory-separator." - if (_Lst.size() >= 2 && _Lst.back().empty() && *(_STD prev(_Lst.end(), 2)) == _Dot_dot) { - _Lst.pop_back(); + if (_Vec.size() >= 2 && _Vec.back().empty() && _Vec.end()[-2] == _Dot_dot) { + _Vec.pop_back(); } - // Build up _Normalized by flattening _Lst. - for (const auto& _Elem : _Lst) { + // Build up _Normalized by flattening _Vec. + for (const auto& _Elem : _Vec) { if (_Elem.empty()) { _Normalized += preferred_separator; } else { @@ -1291,9 +1301,7 @@ namespace filesystem { } // "The result of normalization is a path in normal form, which is said to be normalized." - path _Result(_STD move(_Normalized)); - - return _Result; + return path(_STD move(_Normalized)); } _NODISCARD inline path lexically_relative(const path& _Base) const; @@ -1818,6 +1826,10 @@ namespace filesystem { _THROW(filesystem_error(_Op, _Path1, _Path2, _Make_ec(_Error))); } + [[noreturn]] inline void _Throw_fs_error(const char* _Op, const error_code& _Error) { + _THROW(filesystem_error(_Op, _Error)); + } + [[noreturn]] inline void _Throw_fs_error(const char* _Op, const error_code& _Error, const path& _Path1) { _THROW(filesystem_error(_Op, _Path1, _Error)); } @@ -4042,30 +4054,26 @@ namespace filesystem { return _Result; } - _NODISCARD inline __std_win_error _Current_path(path& _Result) noexcept { + _EXPORT_STD _NODISCARD inline path current_path(error_code& _Ec) { + _Ec.clear(); + path _Result; _Result._Text.resize(__std_fs_max_path); for (;;) { const auto _Requested_size = static_cast(_Result._Text.size()); const auto _Temp_result = __std_fs_get_current_path(_Requested_size, _Result._Text.data()); _Result._Text.resize(_Temp_result._Size); if (_Temp_result._Size < _Requested_size) { - return _Temp_result._Error; + _Ec = _Make_ec(_Temp_result._Error); + return _Result; } } } - _EXPORT_STD _NODISCARD inline path current_path(error_code& _Ec) { - _Ec.clear(); - path _Result; - _Ec = _Make_ec(_Current_path(_Result)); - return _Result; - } - _EXPORT_STD _NODISCARD inline path current_path() { - path _Result; - const auto _Err = _Current_path(_Result); - if (_Err != __std_win_error::_Success) { - _Throw_fs_error("current_path()", _Err); + error_code _Ec; + path _Result(_STD filesystem::current_path(_Ec)); + if (_Ec) { + _Throw_fs_error("current_path()", _Ec); } return _Result; } diff --git a/stl/inc/format b/stl/inc/format index 56f5b11bb6c..fdcf65e7908 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -181,7 +181,7 @@ concept _Parse_spec_callbacks = _Parse_align_callbacks<_Ty, _CharT> && _Parse_precision_callbacks<_Ty, _CharT> && _Width_adapter_callbacks<_Ty, _CharT> && _Precision_adapter_callbacks<_Ty, _CharT> - && requires(_Ty _At, basic_string_view<_CharT> _Sv, _Fmt_align _Aln, _Fmt_sign _Sgn) { + && requires(_Ty _At, _Fmt_sign _Sgn) { { _At._On_sign(_Sgn) } -> same_as; { _At._On_hash() } -> same_as; { _At._On_zero() } -> same_as; @@ -745,10 +745,45 @@ public: } } -private: - template - friend decltype(auto) visit_format_arg(_Visitor&&, basic_format_arg<_Ctx>); + template + decltype(auto) _Visit(_Visitor&& _Vis) { + switch (_Active_state) { + case _Basic_format_arg_type::_None: + return _STD forward<_Visitor>(_Vis)(_No_state); + case _Basic_format_arg_type::_Int_type: + return _STD forward<_Visitor>(_Vis)(_Int_state); + case _Basic_format_arg_type::_UInt_type: + return _STD forward<_Visitor>(_Vis)(_UInt_state); + case _Basic_format_arg_type::_Long_long_type: + return _STD forward<_Visitor>(_Vis)(_Long_long_state); + case _Basic_format_arg_type::_ULong_long_type: + return _STD forward<_Visitor>(_Vis)(_ULong_long_state); + case _Basic_format_arg_type::_Bool_type: + return _STD forward<_Visitor>(_Vis)(_Bool_state); + case _Basic_format_arg_type::_Char_type: + return _STD forward<_Visitor>(_Vis)(_Char_state); + case _Basic_format_arg_type::_Float_type: + return _STD forward<_Visitor>(_Vis)(_Float_state); + case _Basic_format_arg_type::_Double_type: + return _STD forward<_Visitor>(_Vis)(_Double_state); + case _Basic_format_arg_type::_Long_double_type: + return _STD forward<_Visitor>(_Vis)(_Long_double_state); + case _Basic_format_arg_type::_Pointer_type: + return _STD forward<_Visitor>(_Vis)(_Pointer_state); + case _Basic_format_arg_type::_CString_type: + return _STD forward<_Visitor>(_Vis)(_CString_state); + case _Basic_format_arg_type::_String_type: + return _STD forward<_Visitor>(_Vis)(_String_state); + case _Basic_format_arg_type::_Custom_type: + return _STD forward<_Visitor>(_Vis)(_Custom_state); + default: + _STL_VERIFY(false, "basic_format_arg is in impossible state"); + int _Dummy{}; + return _STD forward<_Visitor>(_Vis)(_Dummy); + } + } +private: friend basic_format_args<_Context>; friend _Format_handler<_CharType>; friend _Format_arg_traits<_Context>; @@ -838,39 +873,7 @@ auto _Format_arg_traits<_Context>::_Type_eraser() { _EXPORT_STD template decltype(auto) visit_format_arg(_Visitor&& _Vis, basic_format_arg<_Context> _Arg) { - switch (_Arg._Active_state) { - case _Basic_format_arg_type::_None: - return _STD forward<_Visitor>(_Vis)(_Arg._No_state); - case _Basic_format_arg_type::_Int_type: - return _STD forward<_Visitor>(_Vis)(_Arg._Int_state); - case _Basic_format_arg_type::_UInt_type: - return _STD forward<_Visitor>(_Vis)(_Arg._UInt_state); - case _Basic_format_arg_type::_Long_long_type: - return _STD forward<_Visitor>(_Vis)(_Arg._Long_long_state); - case _Basic_format_arg_type::_ULong_long_type: - return _STD forward<_Visitor>(_Vis)(_Arg._ULong_long_state); - case _Basic_format_arg_type::_Bool_type: - return _STD forward<_Visitor>(_Vis)(_Arg._Bool_state); - case _Basic_format_arg_type::_Char_type: - return _STD forward<_Visitor>(_Vis)(_Arg._Char_state); - case _Basic_format_arg_type::_Float_type: - return _STD forward<_Visitor>(_Vis)(_Arg._Float_state); - case _Basic_format_arg_type::_Double_type: - return _STD forward<_Visitor>(_Vis)(_Arg._Double_state); - case _Basic_format_arg_type::_Long_double_type: - return _STD forward<_Visitor>(_Vis)(_Arg._Long_double_state); - case _Basic_format_arg_type::_Pointer_type: - return _STD forward<_Visitor>(_Vis)(_Arg._Pointer_state); - case _Basic_format_arg_type::_CString_type: - return _STD forward<_Visitor>(_Vis)(_Arg._CString_state); - case _Basic_format_arg_type::_String_type: - return _STD forward<_Visitor>(_Vis)(_Arg._String_state); - case _Basic_format_arg_type::_Custom_type: - return _STD forward<_Visitor>(_Vis)(_Arg._Custom_state); - default: - _STL_VERIFY(false, "basic_format_arg is in impossible state"); - return _STD forward<_Visitor>(_Vis)(0); - } + return _Arg._Visit(_STD forward<_Visitor>(_Vis)); } // we need to implement this ourselves because from_chars does not work with wide characters and isn't constexpr @@ -2086,19 +2089,22 @@ public: } _NODISCARD size_t _Estimate_required_capacity() const noexcept { - using _CharT = typename _Context::char_type; - size_t _Result = 0; - const auto _Visitor = [&_Result](const _ArgTy _Arg) noexcept { - if constexpr (is_same_v<_ArgTy, basic_string_view<_CharT>>) { - _Result += _Arg.size(); - } else if constexpr (is_same_v<_ArgTy, const _CharT*>) { + using _CharType = typename _Context::char_type; + size_t _Result = 0; + + for (size_t _Idx = 0; _Idx < _Num_args; ++_Idx) { + const auto _Packed_index = _Index_array[_Idx]; + const auto _Arg_type = _Packed_index._Type(); + if (_Arg_type == _Basic_format_arg_type::_String_type) { + const auto _Arg_storage = + reinterpret_cast(_Index_array + _Num_args) + _Packed_index._Index; + const auto _View = _Get_value_from_memory>(_Arg_storage); + _Result += _View.size(); + } else if (_Arg_type == _Basic_format_arg_type::_CString_type) { _Result += 32; // estimate for length of null-terminated strings } else { _Result += 8; // estimate for length of all other arguments } - }; - for (size_t _Idx = 0; _Idx < _Num_args; ++_Idx) { - _STD visit_format_arg(_Visitor, get(_Idx)); } return _Result; } @@ -2586,9 +2592,11 @@ _NODISCARD _OutputIt _Write_sign(_OutputIt _Out, const _Fmt_sign _Sgn, const boo return _Out; } -inline void _Buffer_to_uppercase(char* _First, const char* _Last) { +inline void _Buffer_to_uppercase(char* _First, const char* _Last) noexcept { for (; _First != _Last; ++_First) { - *_First = static_cast(_CSTD toupper(*_First)); + if (*_First >= 'a' && *_First <= 'z') { + *_First -= 'a' - 'A'; + } } } @@ -2719,19 +2727,14 @@ _NODISCARD _OutputIt _Write_integral( _Specs._Sgn = _Fmt_sign::_Minus; } - int _Base = 10; - bool _To_upper = false; + int _Base = 10; switch (_Specs._Type) { case 'B': - _To_upper = true; - [[fallthrough]]; case 'b': _Base = 2; break; case 'X': - _To_upper = true; - [[fallthrough]]; case 'x': _Base = 16; break; @@ -2757,7 +2760,7 @@ _NODISCARD _OutputIt _Write_integral( _Buffer_start += 1; } - if (_To_upper) { + if (_Specs._Type == 'X') { _Buffer_to_uppercase(_Buffer_start, _End); } @@ -2864,7 +2867,7 @@ _NODISCARD _OutputIt _Fmt_write( auto _To_upper = false; auto _Format = chars_format::general; - auto _Exponent = '\0'; + auto _Exponent = 'e'; auto _Precision = _Specs._Precision; switch (_Specs._Type) { @@ -2882,8 +2885,7 @@ _NODISCARD _OutputIt _Fmt_write( if (_Precision == -1) { _Precision = 6; } - _Format = chars_format::scientific; - _Exponent = 'e'; + _Format = chars_format::scientific; break; case 'F': _To_upper = true; @@ -2901,8 +2903,7 @@ _NODISCARD _OutputIt _Fmt_write( if (_Precision == -1) { _Precision = 6; } - _Format = chars_format::general; - _Exponent = 'e'; + _Format = chars_format::general; break; } @@ -2964,9 +2965,10 @@ _NODISCARD _OutputIt _Fmt_write( } } + _STL_INTERNAL_CHECK(_Exponent == 'e' || _Exponent == 'p'); if (_To_upper) { _Buffer_to_uppercase(_Buffer_start, _Result.ptr); - _Exponent = static_cast(_CSTD toupper(_Exponent)); + _Exponent -= 'a' - 'A'; } const auto _Is_finite = (_STD isfinite)(_Value); @@ -3015,7 +3017,7 @@ _NODISCARD _OutputIt _Fmt_write( _Zeroes_to_append = _Extra_precision; break; case chars_format::general: - if (_Specs._Alt) { + if (_Specs._Alt && (_Specs._Type == 'g' || _Specs._Type == 'G')) { auto _Digits = static_cast(_Exponent_start - _Buffer_start); if (!_Append_decimal) { diff --git a/stl/inc/functional b/stl/inc/functional index e0e65642859..d3eaf32517c 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -653,38 +653,6 @@ public: extern "C++" [[noreturn]] _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _Xbad_function_call(); -struct _Unforced { // tag to distinguish bind() from bind() - explicit _Unforced() = default; -}; - -// helper to give INVOKE an explicit return type; avoids undesirable Expression SFINAE -template -struct _Invoker_ret { // selected for all _Rx other than _Unforced - template ::template _Is_invocable_r<_Rx>::value, int> = 0> - static _CONSTEXPR20 _Rx _Call(_Fx&& _Func, _Valtys&&... _Vals) noexcept(_Select_invoke_traits<_Fx, - _Valtys...>::template _Is_nothrow_invocable_r<_Rx>::value) { // INVOKE, implicitly converted - if constexpr (is_void_v<_Rx>) { - _STL_INTERNAL_STATIC_ASSERT( - _Select_invoke_traits<_Fx, _Valtys...>::_Is_nothrow_invocable::value - == _Select_invoke_traits<_Fx, _Valtys...>::template _Is_nothrow_invocable_r<_Rx>::value); - _STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...); - } else { - return _STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...); - } - } -}; - -template <> -struct _Invoker_ret<_Unforced> { // selected for _Rx being _Unforced - template - static _CONSTEXPR20 auto _Call(_Fx&& _Func, _Valtys&&... _Vals) noexcept( - _Select_invoke_traits<_Fx, _Valtys...>::_Is_nothrow_invocable::value) - -> decltype(_STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...)) { // INVOKE, unchanged - return _STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...); - } -}; - _EXPORT_STD template class function; @@ -1134,12 +1102,20 @@ public: template _NODISCARD _Fx* target() noexcept { - return reinterpret_cast<_Fx*>(const_cast(this->_Target(typeid(_Fx)))); + if constexpr (is_function_v<_Fx>) { + return nullptr; + } else { + return reinterpret_cast<_Fx*>(const_cast(this->_Target(typeid(_Fx)))); + } } template _NODISCARD const _Fx* target() const noexcept { - return reinterpret_cast(this->_Target(typeid(_Fx))); + if constexpr (is_function_v<_Fx>) { + return nullptr; + } else { + return reinterpret_cast(this->_Target(typeid(_Fx))); + } } #else // _HAS_STATIC_RTTI const type_info& target_type() const noexcept = delete; // requires static RTTI @@ -1984,6 +1960,38 @@ constexpr auto _Fix_arg(_Cv_TiD& _Tid, _Untuple&& _Ut) noexcept( return _Select_fixer<_Cv_TiD>::_Fix(_Tid, _STD move(_Ut)); } +struct _Unforced { // tag to distinguish bind() from bind() + explicit _Unforced() = default; +}; + +// helper to give INVOKE an explicit return type; avoids undesirable Expression SFINAE +template +struct _Invoker_ret { // selected for all _Rx other than _Unforced + template ::template _Is_invocable_r<_Rx>::value, int> = 0> + static _CONSTEXPR20 _Rx _Call(_Fx&& _Func, _Valtys&&... _Vals) noexcept(_Select_invoke_traits<_Fx, + _Valtys...>::template _Is_nothrow_invocable_r<_Rx>::value) { // INVOKE, implicitly converted + if constexpr (is_void_v<_Rx>) { + _STL_INTERNAL_STATIC_ASSERT( + _Select_invoke_traits<_Fx, _Valtys...>::_Is_nothrow_invocable::value + == _Select_invoke_traits<_Fx, _Valtys...>::template _Is_nothrow_invocable_r<_Rx>::value); + _STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...); + } else { + return _STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...); + } + } +}; + +template <> +struct _Invoker_ret<_Unforced> { // selected for _Rx being _Unforced + template + static _CONSTEXPR20 auto _Call(_Fx&& _Func, _Valtys&&... _Vals) noexcept( + _Select_invoke_traits<_Fx, _Valtys...>::_Is_nothrow_invocable::value) + -> decltype(_STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...)) { // INVOKE, unchanged + return _STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...); + } +}; + template _CONSTEXPR20 auto _Call_binder(_Invoker_ret<_Ret>, index_sequence<_Ix...>, _Cv_FD& _Obj, _Cv_tuple_TiD& _Tpl, _Untuple&& _Ut) noexcept(noexcept(_Invoker_ret<_Ret>::_Call(_Obj, @@ -1993,6 +2001,21 @@ _CONSTEXPR20 auto _Call_binder(_Invoker_ret<_Ret>, index_sequence<_Ix...>, _Cv_F return _Invoker_ret<_Ret>::_Call(_Obj, _STD _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...); } +#if _HAS_CXX20 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 +template +concept _Can_call_binder = requires(_CvFD& _Fx, _CvBoundTuple& _Bound_tuple, _UnboundTuple&& _Unbound_tuple) { + _STD _Call_binder(_Invoker_ret<_Ret>{}, _IntSeq{}, _Fx, _Bound_tuple, _STD move(_Unbound_tuple)); +}; +#else // ^^^ concept available / concept unavailable vvv +template +_INLINE_VAR constexpr bool _Can_call_binder = false; + +template +_INLINE_VAR constexpr bool _Can_call_binder<_Ret, _CvFD, _IntSeq, _CvBoundTuple, _UnboundTuple, + void_t{}, _IntSeq{}, _STD declval<_CvFD&>(), + _STD declval<_CvBoundTuple&>(), _STD declval<_UnboundTuple>()))>> = true; +#endif // ^^^ concept unavailable ^^^ + template struct _Forced_result_type { // used by bind() using _RESULT_TYPE_NAME _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS = _Ret; @@ -2011,31 +2034,59 @@ struct _Binder_result_type { // provide result_type (sometimes) template class _Binder : public _Binder_result_type<_Ret, _Fx>::type { // wrap bound callable object and arguments private: - using _Seq = index_sequence_for<_Types...>; - using _First = decay_t<_Fx>; - using _Second = tuple...>; + using _Seq = index_sequence_for<_Types...>; + using _Fd = decay_t<_Fx>; + using _Bound_tuple = tuple...>; - _Compressed_pair<_First, _Second> _Mypair; + _Compressed_pair<_Fd, _Bound_tuple> _Mypair; public: constexpr explicit _Binder(_Fx&& _Func, _Types&&... _Args) : _Mypair(_One_then_variadic_args_t{}, _STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...) {} -#define _CALL_BINDER \ - _Call_binder(_Invoker_ret<_Ret>{}, _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, \ +#define _CALL_BINDER \ + _STD _Call_binder(_Invoker_ret<_Ret>{}, _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, \ _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...)) +#if _HAS_CXX20 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 + template + requires _Can_call_binder<_Ret, _Fd, _Seq, _Bound_tuple, tuple<_Unbound&&...>> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) noexcept(noexcept(_CALL_BINDER)) { + return _CALL_BINDER; + } + + template + void operator()(_Unbound&&...) = delete; + template - _CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) noexcept(noexcept(_CALL_BINDER)) -> decltype(_CALL_BINDER) { + requires _Can_call_binder<_Ret, const _Fd, _Seq, const _Bound_tuple, tuple<_Unbound&&...>> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) const noexcept(noexcept(_CALL_BINDER)) { return _CALL_BINDER; } template - _CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) const noexcept(noexcept(_CALL_BINDER)) - -> decltype(_CALL_BINDER) { + void operator()(_Unbound&&...) const = delete; +#else // ^^^ requires available / requires unavailable vvv + template >, int> = 0> + _CONSTEXPR20 decltype(auto) operator()(_Unbound&&... _Unbargs) noexcept(noexcept(_CALL_BINDER)) { + return _CALL_BINDER; + } + + template >, int> = 0> + void operator()(_Unbound&&...) = delete; + + template >, int> = 0> + _CONSTEXPR20 decltype(auto) operator()(_Unbound&&... _Unbargs) const noexcept(noexcept(_CALL_BINDER)) { return _CALL_BINDER; } + template >, int> = 0> + void operator()(_Unbound&&...) const = delete; +#endif // ^^^ requires unavailable ^^^ #undef _CALL_BINDER }; @@ -2083,6 +2134,27 @@ constexpr auto _Call_front_binder(index_sequence<_Ix...>, _Cv_FD&& _Obj, _Cv_tup _STD forward<_Unbound>(_Unbargs)...); } +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 +template +concept _Can_call_front_binder = requires(_CvFD&& _Fx, _CvBoundTuple&& _Bound_tuple, _Unbound&&... _Unbound_args) { + _STD _Call_front_binder(_IntSeq{}, _STD forward<_CvFD>(_Fx), _STD forward<_CvBoundTuple>(_Bound_tuple), + _STD forward<_Unbound>(_Unbound_args)...); +}; +#else // ^^^ concept available / concept unavailable vvv +template +inline constexpr bool _Can_call_front_binder_impl = false; + +template +inline constexpr bool + _Can_call_front_binder_impl(), + _STD declval<_CvBoundTuple>(), _STD declval<_Unbound>()...))>, + _IntSeq, _CvFD, _CvBoundTuple, _Unbound...> = true; + +template +inline constexpr bool _Can_call_front_binder = + _Can_call_front_binder_impl; +#endif // ^^^ concept unavailable ^^^ + template class _Front_binder { // wrap bound callable object and arguments private: @@ -2099,39 +2171,98 @@ public: constexpr explicit _Front_binder(_FxInit&& _Func, _TypesInit&&... _Args) : _Mypair(_One_then_variadic_args_t{}, _STD forward<_FxInit>(_Func), _STD forward<_TypesInit>(_Args)...) {} +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 + template + requires _Can_call_front_binder<_Seq, _Fx&, tuple<_Types...>&, _Unbound...> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) & noexcept(noexcept( + _STD _Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_front_binder( + _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...); + } + + template + void operator()(_Unbound&&...) & = delete; + template - constexpr auto operator()(_Unbound&&... _Unbargs) & noexcept(noexcept( - _Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...))) - -> decltype(_Call_front_binder( - _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...)) { - return _Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...); + requires _Can_call_front_binder<_Seq, const _Fx&, const tuple<_Types...>&, _Unbound...> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) const& noexcept(noexcept( + _STD _Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_front_binder( + _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...); } template - constexpr auto operator()(_Unbound&&... _Unbargs) const& noexcept(noexcept( - _Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...))) - -> decltype(_Call_front_binder( - _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...)) { - return _Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...); + void operator()(_Unbound&&...) const& = delete; + + template + requires _Can_call_front_binder<_Seq, _Fx, tuple<_Types...>, _Unbound...> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) && noexcept(noexcept(_STD _Call_front_binder( + _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_front_binder( + _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...); } template - constexpr auto operator()(_Unbound&&... _Unbargs) && noexcept(noexcept(_Call_front_binder( - _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...))) - -> decltype(_Call_front_binder( - _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...)) { - return _Call_front_binder( + void operator()(_Unbound&&...) && = delete; + + template + requires _Can_call_front_binder<_Seq, const _Fx, const tuple<_Types...>, _Unbound...> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) const&& noexcept(noexcept(_STD _Call_front_binder( + _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_front_binder( _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...); } template - constexpr auto operator()(_Unbound&&... _Unbargs) const&& noexcept(noexcept(_Call_front_binder( - _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...))) - -> decltype(_Call_front_binder( - _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...)) { - return _Call_front_binder( + void operator()(_Unbound&&...) const&& = delete; +#else // ^^^ requires available / requires unavailable vvv + template &, _Unbound...>, int> = 0> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) & noexcept(noexcept( + _STD _Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_front_binder( + _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...); + } + + template &, _Unbound...>, int> = 0> + void operator()(_Unbound&&...) & = delete; + + template &, _Unbound...>, int> = 0> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) const& noexcept(noexcept( + _STD _Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_front_binder( + _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...); + } + + template &, _Unbound...>, int> = 0> + void operator()(_Unbound&&...) const& = delete; + + template , _Unbound...>, int> = 0> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) && noexcept(noexcept(_STD _Call_front_binder( + _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_front_binder( _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...); } + + template , _Unbound...>, int> = 0> + void operator()(_Unbound&&...) && = delete; + + template , _Unbound...>, int> = 0> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) const&& noexcept(noexcept(_STD _Call_front_binder( + _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_front_binder( + _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...); + } + + template , _Unbound...>, int> = 0> + void operator()(_Unbound&&...) const&& = delete; +#endif // ^^^ requires unavailable ^^^ }; _EXPORT_STD template @@ -2160,6 +2291,27 @@ constexpr auto _Call_back_binder(index_sequence<_Ix...>, _Cv_FD&& _Obj, _Cv_tupl _STD get<_Ix>(_STD forward<_Cv_tuple_TiD>(_Tpl))...); } +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 +template +concept _Can_call_back_binder = requires(_CvFD&& _Fx, _CvBoundTuple&& _Bound_tuple, _Unbound&&... _Unbound_args) { + _STD _Call_back_binder(_IntSeq{}, _STD forward<_CvFD>(_Fx), _STD forward<_CvBoundTuple>(_Bound_tuple), + _STD forward<_Unbound>(_Unbound_args)...); +}; +#else // ^^^ concept available / concept unavailable vvv +template +inline constexpr bool _Can_call_back_binder_impl = false; + +template +inline constexpr bool + _Can_call_back_binder_impl(), + _STD declval<_CvBoundTuple>(), _STD declval<_Unbound>()...))>, + _IntSeq, _CvFD, _CvBoundTuple, _Unbound...> = true; + +template +inline constexpr bool _Can_call_back_binder = + _Can_call_back_binder_impl; +#endif // ^^^ concept unavailable ^^^ + template class _Back_binder { // wrap bound callable object and arguments private: @@ -2176,39 +2328,97 @@ public: constexpr explicit _Back_binder(_FxInit&& _Func, _TypesInit&&... _Args) : _Mypair(_One_then_variadic_args_t{}, _STD forward<_FxInit>(_Func), _STD forward<_TypesInit>(_Args)...) {} +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 template - constexpr auto operator()(_Unbound&&... _Unbargs) & noexcept( - noexcept(_Call_back_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...))) - -> decltype(_Call_back_binder( - _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...)) { - return _Call_back_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...); + requires _Can_call_back_binder<_Seq, _Fx&, tuple<_Types...>&, _Unbound...> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) & noexcept(noexcept( + _STD _Call_back_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_back_binder( + _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...); } template - constexpr auto operator()(_Unbound&&... _Unbargs) const& noexcept( - noexcept(_Call_back_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...))) - -> decltype(_Call_back_binder( - _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...)) { - return _Call_back_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...); + void operator()(_Unbound&&...) & = delete; + + template + requires _Can_call_back_binder<_Seq, const _Fx&, const tuple<_Types...>&, _Unbound...> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) const& noexcept(noexcept( + _STD _Call_back_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_back_binder( + _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...); } template - constexpr auto operator()(_Unbound&&... _Unbargs) && noexcept(noexcept(_Call_back_binder( - _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...))) - -> decltype(_Call_back_binder( - _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...)) { - return _Call_back_binder( + void operator()(_Unbound&&...) const& = delete; + + template + requires _Can_call_back_binder<_Seq, _Fx, tuple<_Types...>, _Unbound...> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) && noexcept(noexcept(_STD _Call_back_binder( + _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_back_binder( _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...); } template - constexpr auto operator()(_Unbound&&... _Unbargs) const&& noexcept(noexcept(_Call_back_binder( - _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...))) - -> decltype(_Call_back_binder( - _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...)) { - return _Call_back_binder( + void operator()(_Unbound&&...) && = delete; + + template + requires _Can_call_back_binder<_Seq, const _Fx, const tuple<_Types...>, _Unbound...> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) const&& noexcept(noexcept(_STD _Call_back_binder( + _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_back_binder( _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...); } + + template + void operator()(_Unbound&&...) const&& = delete; +#else // ^^^ requires available / requires unavailable vvv + template &, _Unbound...>, int> = 0> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) & noexcept(noexcept( + _STD _Call_back_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_back_binder( + _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...); + } + + template &, _Unbound...>, int> = 0> + void operator()(_Unbound&&...) & = delete; + + template &, _Unbound...>, int> = 0> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) const& noexcept(noexcept( + _STD _Call_back_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_back_binder( + _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...); + } + + template &, _Unbound...>, int> = 0> + void operator()(_Unbound&&...) const& = delete; + + template , _Unbound...>, int> = 0> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) && noexcept(noexcept(_STD _Call_back_binder( + _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_back_binder( + _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...); + } + + template , _Unbound...>, int> = 0> + void operator()(_Unbound&&...) && = delete; + + template , _Unbound...>, int> = 0> + constexpr decltype(auto) operator()(_Unbound&&... _Unbargs) const&& noexcept(noexcept(_STD _Call_back_binder( + _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...))) { + return _STD _Call_back_binder( + _Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...); + } + + template , _Unbound...>, int> = 0> + void operator()(_Unbound&&...) const&& = delete; +#endif // ^^^ requires unavailable ^^^ }; _EXPORT_STD template diff --git a/stl/inc/iterator b/stl/inc/iterator index 180abaa4c2f..48089f6d0a9 100644 --- a/stl/inc/iterator +++ b/stl/inc/iterator @@ -1467,27 +1467,39 @@ struct iterator_traits> : iterator_traits<_Iter> { _STD_END _STDEXT_BEGIN -using _STD iterator_traits; using _STD size_t; template -class checked_array_iterator { // wrap a pointer with checking - static_assert(_STD is_pointer_v<_Ptr>, "checked_array_iterator requires pointers"); +class _DEPRECATE_STDEXT_ARR_ITERS checked_array_iterator { // wrap a pointer with checking +private: + using _Pointee_type = _STD remove_pointer_t<_Ptr>; + static_assert(_STD is_pointer_v<_Ptr> && _STD is_object_v<_Pointee_type>, + "checked_array_iterator requires pointers to objects"); public: - using iterator_category = typename iterator_traits<_Ptr>::iterator_category; - using value_type = typename iterator_traits<_Ptr>::value_type; - using difference_type = typename iterator_traits<_Ptr>::difference_type; - using pointer = typename iterator_traits<_Ptr>::pointer; - using reference = typename iterator_traits<_Ptr>::reference; + using iterator_category = _STD random_access_iterator_tag; + using value_type = _STD remove_cv_t<_Pointee_type>; + using difference_type = _STD ptrdiff_t; + using pointer = _Ptr; + using reference = _Pointee_type&; +#ifdef __cpp_lib_concepts + using iterator_concept = _STD contiguous_iterator_tag; +#endif // __cpp_lib_concepts - constexpr checked_array_iterator() noexcept : _Myarray(nullptr), _Mysize(0), _Myindex(0) {} + constexpr checked_array_iterator() = default; constexpr checked_array_iterator(const _Ptr _Array, const size_t _Size, const size_t _Index = 0) noexcept : _Myarray(_Array), _Mysize(_Size), _Myindex(_Index) { _STL_VERIFY(_Index <= _Size, "checked_array_iterator construction index out of range"); } + _STL_DISABLE_DEPRECATED_WARNING + template , int> = 0> + constexpr operator checked_array_iterator() const noexcept { + return checked_array_iterator{_Myarray, _Mysize, _Myindex}; + } + _STL_RESTORE_DEPRECATED_WARNING + _NODISCARD constexpr _Ptr base() const noexcept { return _Myarray + _Myindex; } @@ -1658,32 +1670,47 @@ public: } private: - _Ptr _Myarray; // beginning of array - size_t _Mysize; // size of array - size_t _Myindex; // offset into array + _Ptr _Myarray = nullptr; // beginning of array + size_t _Mysize = 0; // size of array + size_t _Myindex = 0; // offset into array }; +_STL_DISABLE_DEPRECATED_WARNING template -_NODISCARD constexpr checked_array_iterator<_Ptr> make_checked_array_iterator( - const _Ptr _Array, const size_t _Size, const size_t _Index = 0) { +_DEPRECATE_STDEXT_ARR_ITERS _NODISCARD constexpr checked_array_iterator<_Ptr> make_checked_array_iterator( + const _Ptr _Array, const size_t _Size, const size_t _Index = 0) noexcept { return checked_array_iterator<_Ptr>(_Array, _Size, _Index); } +_STL_RESTORE_DEPRECATED_WARNING template -class unchecked_array_iterator { // wrap a pointer without checking, to silence warnings - static_assert(_STD is_pointer_v<_Ptr>, "unchecked_array_iterator requires pointers"); +class _DEPRECATE_STDEXT_ARR_ITERS unchecked_array_iterator { // wrap a pointer without checking, to silence warnings +private: + using _Pointee_type = _STD remove_pointer_t<_Ptr>; + static_assert(_STD is_pointer_v<_Ptr> && _STD is_object_v<_Pointee_type>, + "unchecked_array_iterator requires pointers to objects"); public: - using iterator_category = typename iterator_traits<_Ptr>::iterator_category; - using value_type = typename iterator_traits<_Ptr>::value_type; - using difference_type = typename iterator_traits<_Ptr>::difference_type; - using pointer = typename iterator_traits<_Ptr>::pointer; - using reference = typename iterator_traits<_Ptr>::reference; + using iterator_category = _STD random_access_iterator_tag; + using value_type = _STD remove_cv_t<_Pointee_type>; + using difference_type = _STD ptrdiff_t; + using pointer = _Ptr; + using reference = _Pointee_type&; +#ifdef __cpp_lib_concepts + using iterator_concept = _STD contiguous_iterator_tag; +#endif // __cpp_lib_concepts - constexpr unchecked_array_iterator() noexcept : _Myptr(nullptr) {} + constexpr unchecked_array_iterator() = default; constexpr explicit unchecked_array_iterator(const _Ptr _Src) noexcept : _Myptr(_Src) {} + _STL_DISABLE_DEPRECATED_WARNING + template , int> = 0> + constexpr operator unchecked_array_iterator() const noexcept { + return unchecked_array_iterator{_Myptr}; + } + _STL_RESTORE_DEPRECATED_WARNING + _NODISCARD constexpr _Ptr base() const noexcept { return _Myptr; } @@ -1802,15 +1829,35 @@ public: } private: - _Ptr _Myptr; // underlying pointer + _Ptr _Myptr = nullptr; // underlying pointer }; +_STL_DISABLE_DEPRECATED_WARNING template -_NODISCARD unchecked_array_iterator<_Ptr> make_unchecked_array_iterator(const _Ptr _It) noexcept { +_DEPRECATE_STDEXT_ARR_ITERS _NODISCARD unchecked_array_iterator<_Ptr> make_unchecked_array_iterator( + const _Ptr _It) noexcept { return unchecked_array_iterator<_Ptr>(_It); } +_STL_RESTORE_DEPRECATED_WARNING _STDEXT_END +#if _HAS_CXX20 +_STD_BEGIN +_STL_DISABLE_DEPRECATED_WARNING +template +struct pointer_traits<_STDEXT checked_array_iterator<_Ty*>> { + using pointer = _STDEXT checked_array_iterator<_Ty*>; + using element_type = _Ty; + using difference_type = ptrdiff_t; + + _NODISCARD static constexpr element_type* to_address(const pointer _Iter) noexcept { + return _Iter._Unwrapped(); + } +}; +_STL_RESTORE_DEPRECATED_WARNING +_STD_END +#endif // _HAS_CXX20 + #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) diff --git a/stl/inc/memory b/stl/inc/memory index 00a358493d1..8cc86b2ccb3 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -1879,12 +1879,7 @@ _NODISCARD bool operator==(const shared_ptr<_Ty1>& _Left, const shared_ptr<_Ty2> #if _HAS_CXX20 _EXPORT_STD template _NODISCARD strong_ordering operator<=>(const shared_ptr<_Ty1>& _Left, const shared_ptr<_Ty2>& _Right) noexcept { -#if !defined(__EDG__) && !defined(__clang__) // TRANSITION, DevCom-10334808 - using _Common_ptr_t = decltype(false ? _Left.get() : _Right.get()); - return static_cast<_Common_ptr_t>(_Left.get()) <=> static_cast<_Common_ptr_t>(_Right.get()); -#else // ^^^ workaround / no workaround vvv return _Left.get() <=> _Right.get(); -#endif // ^^^ no workaround ^^^ } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template @@ -4003,6 +3998,10 @@ public: store(_STD move(_Value)); } + void operator=(nullptr_t) noexcept { + store(nullptr); + } + ~atomic() { const auto _Rep = this->_Repptr._Unsafe_load_relaxed(); if (_Rep) { diff --git a/stl/inc/mutex b/stl/inc/mutex index 1d4faf58c49..a17c022650c 100644 --- a/stl/inc/mutex +++ b/stl/inc/mutex @@ -49,7 +49,7 @@ struct _Mtx_internal_imp_mirror { static constexpr size_t _Critical_section_align = alignof(void*); int _Type; - _Aligned_storage_t<_Critical_section_size, _Critical_section_align> _Cs; + _Aligned_storage_t<_Critical_section_size, _Critical_section_align> _Cs_storage; long _Thread_id; int _Count; }; @@ -93,11 +93,7 @@ public: _Mtx_unlock(_Mymtx()); } - using native_handle_type = void*; - - _NODISCARD native_handle_type native_handle() noexcept /* strengthened */ { - return _Mtx_getconcrtcs(_Mymtx()); - } + // native_handle_type and native_handle() have intentionally been removed. See GH-3820. protected: _NODISCARD_TRY_CHANGE_STATE bool _Verify_ownership_levels() noexcept { @@ -636,8 +632,6 @@ _EXPORT_STD enum class cv_status { // names for wait returns _EXPORT_STD class condition_variable { // class for waiting for conditions public: - using native_handle_type = _Cnd_t; - condition_variable() noexcept /* strengthened */ { _Cnd_init_in_situ(_Mycnd()); } @@ -725,9 +719,7 @@ public: return _Wait_until1(_Lck, _Abs_time, _Pred); } - _NODISCARD native_handle_type native_handle() noexcept /* strengthened */ { - return _Mycnd(); - } + // native_handle_type and native_handle() have intentionally been removed. See GH-3820. void _Register(unique_lock& _Lck, int* _Ready) noexcept { // register this object for release at thread exit _Cnd_register_at_thread_exit(_Mycnd(), _Lck.release()->_Mymtx(), _Ready); diff --git a/stl/inc/ostream b/stl/inc/ostream index 6658a75d81e..beef34bae1e 100644 --- a/stl/inc/ostream +++ b/stl/inc/ostream @@ -1126,7 +1126,7 @@ void _Vprint_nonunicode_impl( _Ostr.setstate(_State); } -template +_EXPORT_STD /* TRANSITION, VSO-1538698 */ template ios_base::iostate _Print_noformat_unicode(ostream& _Ostr, const string_view _Str) { // *LOCKED* // diff --git a/stl/inc/random b/stl/inc/random index 6960de75eb3..d892acd566e 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -61,10 +61,10 @@ using _Enable_if_seed_seq_t = && !is_same_v, _Self> && !is_same_v, _Engine>, int>; -_INLINE_VAR constexpr long double _Pi = 3.14159265358979323846264338327950288L; -_INLINE_VAR constexpr long double _Exp1 = 2.71828182845904523536028747135266250L; -_INLINE_VAR constexpr long double _Two32 = 4294967296.0L; -_INLINE_VAR constexpr long double _Two31 = 2147483648.0L; +_INLINE_VAR constexpr long double _Pi_val = 3.14159265358979323846264338327950288L; +_INLINE_VAR constexpr long double _Exp1 = 2.71828182845904523536028747135266250L; +_INLINE_VAR constexpr long double _Two32 = 4294967296.0L; +_INLINE_VAR constexpr long double _Two31 = 2147483648.0L; extern "C++" _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _XLgamma(float); extern "C++" _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _XLgamma(double); @@ -2466,7 +2466,7 @@ private: _Ty _Res; _Ty1 _Yx; for (;;) { // generate a tentative value - _Yx = static_cast<_Ty1>(_CSTD tan(_Pi * _NRAND(_Eng, _Ty1))); + _Yx = static_cast<_Ty1>(_CSTD tan(_Pi_val * _NRAND(_Eng, _Ty1))); const _Ty1 _Mx{_Par0._Sqrt * _Yx + _Par0._Mean}; if (0.0 <= _Mx && _Mx < _Ty1_max) { _Res = static_cast<_Ty>(_Mx); @@ -2661,7 +2661,7 @@ private: for (;;) { // generate and reject _Ty1 _Yx; for (;;) { // generate a tentative value - _Yx = static_cast<_Ty1>(_CSTD tan(_Pi * _NRAND(_Eng, _Ty1))); + _Yx = static_cast<_Ty1>(_CSTD tan(_Pi_val * _NRAND(_Eng, _Ty1))); const _Ty1 _Mx{_Par0._Sqrt * _Yx + _Par0._Mean}; if (0.0 <= _Mx && _Mx < _Ty1_Tx) { _Res = static_cast<_Ty>(_Mx); @@ -3317,7 +3317,7 @@ private: // no shortcuts for (;;) { // generate and reject - _Yx = static_cast<_Ty>(_CSTD tan(_Pi * _NRAND(_Eng, _Ty))); + _Yx = static_cast<_Ty>(_CSTD tan(_Pi_val * _NRAND(_Eng, _Ty))); _Xx = _Par0._Sqrt * _Yx + _Par0._Alpha - 1; if (0 < _Xx && _NRAND(_Eng, _Ty) <= (1 + _Yx * _Yx) @@ -3949,7 +3949,7 @@ private: template result_type _Eval(_Engine& _Eng, const param_type& _Par0) const { // generate pseudo-random value _Ty Px = _NRAND(_Eng, _Ty); - return static_cast<_Ty>(_Par0._Ax + _Par0._Bx * _CSTD tan(_Pi * (Px - static_cast<_Ty>(0.5)))); + return static_cast<_Ty>(_Par0._Ax + _Par0._Bx * _CSTD tan(_Pi_val * (Px - static_cast<_Ty>(0.5)))); } param_type _Par; diff --git a/stl/inc/ranges b/stl/inc/ranges index 753272269d1..fe82e889990 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -38,6 +38,9 @@ namespace ranges { template inline constexpr bool _Is_initializer_list = _Is_specialization_v, initializer_list>; + template // _Require_constant is a valid template-id iff E is a constant expression of structural type + struct _Require_constant; + #if _HAS_CXX23 _EXPORT_STD template using const_iterator_t = const_iterator>; @@ -47,6 +50,34 @@ namespace ranges { _EXPORT_STD template using range_const_reference_t = iter_const_reference_t>; + + template + inline constexpr auto _Compile_time_max_size = + (numeric_limits<_Make_unsigned_like_t>>::max)(); + + template + inline constexpr auto _Compile_time_max_size<_Ty> = (numeric_limits>::max)(); + + template + requires requires { typename _Require_constant<_Ty::size()>; } + inline constexpr auto _Compile_time_max_size<_Ty> = _Ty::size(); + + template + inline constexpr auto _Compile_time_max_size<_Ty[_Size]> = _Size; + + template + inline constexpr auto _Compile_time_max_size> = _Size; + + template + inline constexpr auto _Compile_time_max_size> = _Size; + + template + requires (_Extent != dynamic_extent) + inline constexpr auto _Compile_time_max_size> = _Extent; + + template + requires (_Extent != dynamic_extent) + inline constexpr auto _Compile_time_max_size> = _Extent; #endif // _HAS_CXX23 // clang-format off @@ -1828,6 +1859,14 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = true; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; +#endif // _HAS_CXX23 + _EXPORT_STD template requires (movable<_Rng> && !_Is_initializer_list<_Rng>) class owning_view : public view_interface> { @@ -1915,6 +1954,14 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { template concept _Can_ref_view = requires(_Rng&& __r) { ref_view{static_cast<_Rng&&>(__r)}; }; @@ -2050,6 +2097,14 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { template concept _Can_as_rvalue = requires(_Rng&& __r) { as_rvalue_view{static_cast<_Rng&&>(__r)}; }; @@ -2327,6 +2382,11 @@ namespace ranges { template filter_view(_Rng&&, _Pr) -> filter_view, _Pr>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; +#endif // _HAS_CXX23 + namespace views { struct _Filter_fn { // clang-format off @@ -2757,6 +2817,14 @@ namespace ranges { template transform_view(_Rng&&, _Fn) -> transform_view, _Fn>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { struct _Transform_fn { // clang-format off @@ -2970,6 +3038,14 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { template concept _Random_sized_range = random_access_range<_Rng> && sized_range<_Rng>; @@ -3211,6 +3287,14 @@ namespace ranges { template take_while_view(_Rng&&, _Pr) -> take_while_view, _Pr>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { struct _Take_while_fn { template @@ -3360,6 +3444,14 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { class _Drop_fn { private: @@ -3525,6 +3617,11 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; +#endif // _HAS_CXX23 + namespace views { struct _Drop_while_fn { template @@ -3940,6 +4037,30 @@ namespace ranges { template explicit join_view(_Rng&&) -> join_view>; +#if _HAS_CXX23 + template + _NODISCARD consteval auto _Join_view_compile_time_max_size() { + using _Inner = remove_reference_t>; + using _Size_type = + common_type_t), decltype(_Compile_time_max_size<_Inner>)>; + _Size_type _Result{}; + const bool _Overflow = _Mul_overflow(static_cast<_Size_type>(_Compile_time_max_size<_Rng>), + static_cast<_Size_type>(_Compile_time_max_size<_Inner>), _Result); + if (_Overflow) { + return (numeric_limits<_Size_type>::max)(); + } else { + return _Result; + } + } + + template + inline constexpr auto _Compile_time_max_size> = _Join_view_compile_time_max_size<_Rng>(); + + template + inline constexpr auto _Compile_time_max_size> = + _Join_view_compile_time_max_size(); +#endif // _HAS_CXX23 + namespace views { class _Join_fn : public _Pipe::_Base<_Join_fn> { public: @@ -4447,6 +4568,37 @@ namespace ranges { join_with_view(_Rng&&, range_value_t>) -> join_with_view, single_view>>>; +#if _HAS_CXX23 + template + _NODISCARD consteval auto _Join_with_view_compile_time_max_size() { + using _Inner = remove_reference_t>; + using _Size_type = common_type_t), + decltype(_Compile_time_max_size<_Inner>), decltype(_Compile_time_max_size<_Pat>)>; + _Size_type _Joined_max_size{}; + _Size_type _Pattern_max_size{}; + _Size_type _Result{}; + const bool _Overflow = + _Mul_overflow(static_cast<_Size_type>(_Compile_time_max_size<_Rng>), + static_cast<_Size_type>(_Compile_time_max_size<_Inner>), _Joined_max_size) + || _Mul_overflow((_STD max)(static_cast<_Size_type>(_Compile_time_max_size<_Rng>), _Size_type{1}) - 1, + static_cast<_Size_type>(_Compile_time_max_size<_Pat>), _Pattern_max_size) + || _Add_overflow(_Joined_max_size, _Pattern_max_size, _Result); + if (_Overflow) { + return (numeric_limits<_Size_type>::max)(); + } else { + return _Result; + } + } + + template + inline constexpr auto _Compile_time_max_size> = + _Join_with_view_compile_time_max_size<_Rng, _Pat>(); + + template + inline constexpr auto _Compile_time_max_size> = + _Join_with_view_compile_time_max_size(); +#endif // _HAS_CXX23 + namespace views { struct _Join_with_fn { // clang-format off @@ -4471,9 +4623,6 @@ namespace ranges { } // namespace views #endif // _HAS_CXX23 - template // _Require_constant is a valid template-id iff E is a constant expression of structural type - struct _Require_constant; - // clang-format off template concept _Tiny_range = sized_range<_Ty> @@ -4596,7 +4745,7 @@ namespace ranges { constexpr _Outer_iter(_Outer_iter _It) requires _Const && convertible_to, iterator_t<_BaseTy>> - : _Mybase{_STD move(_It._Current)}, _Parent{_It._Parent} {} + : _Mybase{_STD move(_It._Current)}, _Parent{_It._Parent}, _Trailing_empty{_It._Trailing_empty} {} _NODISCARD constexpr auto operator*() const noexcept(noexcept(value_type{*this})) /* strengthened */ { return value_type{*this}; @@ -4868,6 +5017,15 @@ namespace ranges { lazy_split_view(_Rng&&, range_value_t<_Rng>) -> lazy_split_view, single_view>>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = + _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { struct _Lazy_split_fn { // clang-format off @@ -5064,6 +5222,11 @@ namespace ranges { template split_view(_Rng&&, range_value_t<_Rng>) -> split_view, single_view>>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; +#endif // _HAS_CXX23 + namespace views { struct _Split_fn { // clang-format off @@ -5214,6 +5377,14 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { class _Common_fn : public _Pipe::_Base<_Common_fn> { private: @@ -5333,6 +5504,14 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { template concept _Can_extract_base = requires(_Rng&& __r) { static_cast<_Rng&&>(__r).base(); }; @@ -5470,6 +5649,14 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { template concept _Can_as_const = requires(_Rng&& __r) { as_const_view{static_cast<_Rng&&>(__r)}; }; @@ -5940,6 +6127,15 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = + _Compile_time_max_size; +#endif // _HAS_CXX23 + _EXPORT_STD template using keys_view = elements_view<_Rng, 0>; _EXPORT_STD template @@ -6124,7 +6320,7 @@ namespace ranges { } _NODISCARD_FRIEND constexpr difference_type operator-( - const _Iterator& _Left, const _Iterator& _Right) noexcept /* strengthened */ { + const _Iterator& _Left, const _Iterator& _Right) noexcept { return _Left._Pos - _Right._Pos; } @@ -6282,6 +6478,14 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { class _Enumerate_fn : public _Pipe::_Base<_Enumerate_fn> { public: @@ -6876,6 +7080,15 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Vw> && forward_range<_Vw>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + requires forward_range<_Rng> + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { struct _Chunk_fn { // clang-format off @@ -7268,6 +7481,14 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Vw>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { struct _Slide_fn { // clang-format off @@ -7467,6 +7688,11 @@ namespace ranges { template chunk_by_view(_Rng&&, _Pr) -> chunk_by_view, _Pr>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; +#endif // _HAS_CXX23 + namespace views { struct _Chunk_by_fn { // clang-format off @@ -7856,6 +8082,14 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Vw>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + namespace views { struct _Stride_fn { // clang-format off @@ -8349,6 +8583,21 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = (enable_borrowed_range<_ViewTypes> && ...); +#if _HAS_CXX23 + template + _NODISCARD consteval auto _Zip_view_compile_time_max_size() { + using _Size_type = common_type_t)...>; + return (_STD min)({static_cast<_Size_type>(_Compile_time_max_size<_Rngs>)...}); + } + + template + inline constexpr auto _Compile_time_max_size> = _Zip_view_compile_time_max_size<_Rngs...>(); + + template + inline constexpr auto _Compile_time_max_size> = + _Zip_view_compile_time_max_size(); +#endif // _HAS_CXX23 + namespace views { struct _Zip_fn { private: @@ -8687,6 +8936,16 @@ namespace ranges { template zip_transform_view(_Func, _Ranges&&...) -> zip_transform_view<_Func, views::all_t<_Ranges>...>; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = + _Compile_time_max_size>; + + template + inline constexpr auto _Compile_time_max_size> = + _Compile_time_max_size>; +#endif // _HAS_CXX23 + namespace views { struct _Zip_transform_fn { private: @@ -9143,6 +9402,24 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; +#if _HAS_CXX23 + template + _NODISCARD consteval auto _Adjacent_view_compile_time_max_size() { + using _Size_type = common_type_t), size_t>; + auto _Size = static_cast<_Size_type>(_Compile_time_max_size<_Rng>); + _Size -= (_STD min)(_Size, static_cast<_Size_type>(_Nx - 1)); + return static_cast<_Size_type>(_Size); + } + + template + inline constexpr auto _Compile_time_max_size> = + _Adjacent_view_compile_time_max_size<_Rng, _Nx>(); + + template + inline constexpr auto _Compile_time_max_size> = + _Adjacent_view_compile_time_max_size(); +#endif // _HAS_CXX23 + namespace views { template class _Adjacent_fn : public _Pipe::_Base<_Adjacent_fn<_Nx>> { @@ -9478,6 +9755,16 @@ namespace ranges { } }; +#if _HAS_CXX23 + template + inline constexpr auto _Compile_time_max_size> = + _Compile_time_max_size>; + + template + inline constexpr auto _Compile_time_max_size> = + _Compile_time_max_size>; +#endif // _HAS_CXX23 + namespace views { template class _Adjacent_transform_fn { @@ -9551,69 +9838,28 @@ namespace ranges { } } - template - inline constexpr auto _Compile_time_max_size = (numeric_limits>::max)(); - - template - concept _Constant_sized_range = - sized_range<_Ty> && requires { typename _Require_constant::size()>; }; - - template <_Constant_sized_range _Ty> - inline constexpr auto _Compile_time_max_size<_Ty> = remove_reference_t<_Ty>::size(); - - template - inline constexpr auto _Compile_time_max_size> = _Size; - - template - inline constexpr auto _Compile_time_max_size> = _Size; - - template - requires (_Extent != dynamic_extent) - inline constexpr auto _Compile_time_max_size> = _Extent; - - template - requires (_Extent != dynamic_extent) - inline constexpr auto _Compile_time_max_size> = _Extent; - - template - inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Ty>; - - template - requires sized_range - inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; - - template - inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Ty>; - - template - requires sized_range - inline constexpr auto _Compile_time_max_size> = _Compile_time_max_size; - - template - _NODISCARD consteval int _Cartesian_product_max_size_bit_width() noexcept { - if constexpr (sized_range<_Rng>) { - if constexpr (requires(range_size_t<_Rng> _Val) { _STD bit_width(_Val); }) { - return _STD bit_width(_Compile_time_max_size<_Rng>); - } else { - return numeric_limits>::digits; - } + template + _NODISCARD consteval int _Cartesian_product_max_size_bit_width() { + using _Size_type = decltype(_Compile_time_max_size<_Rng>); + if constexpr (requires(_Size_type _Val) { _STD bit_width(_Val); }) { + return _STD bit_width(_Compile_time_max_size<_Rng>); } else { - return numeric_limits<_Make_unsigned_like_t>>::digits; + return numeric_limits<_Size_type>::digits; } } - template + template + requires (sizeof...(_Rngs) > 0) _NODISCARD consteval auto _Cartesian_product_optimal_size_type() noexcept { - constexpr int _Optimal_size_type_bit_width = - (_Cartesian_product_max_size_bit_width<_First>() + ... + _Cartesian_product_max_size_bit_width<_Rest>()); + constexpr int _Optimal_size_type_bit_width = (_Cartesian_product_max_size_bit_width<_Rngs>() + ...); if constexpr (_Optimal_size_type_bit_width <= 8) { - return uint_least8_t{}; + return uint8_t{}; } else if constexpr (_Optimal_size_type_bit_width <= 16) { - return uint_least16_t{}; + return uint16_t{}; } else if constexpr (_Optimal_size_type_bit_width <= 32) { - return uint_least32_t{}; + return uint32_t{}; } else if constexpr (_Optimal_size_type_bit_width <= 64) { - return uint_least64_t{}; + return uint64_t{}; } else { return _Unsigned128{}; } @@ -10037,6 +10283,30 @@ namespace ranges { template cartesian_product_view(_Rngs&&...) -> cartesian_product_view...>; +#if _HAS_CXX23 + template + _NODISCARD consteval auto _Cartesian_product_view_compile_time_max_size() { + using _Size_type = common_type_t()), + decltype(_Compile_time_max_size<_Rngs>)...>; + _Size_type _Result{1}; + const bool _Overflow = + (_Mul_overflow(static_cast<_Size_type>(_Compile_time_max_size<_Rngs>), _Result, _Result) || ...); + if (_Overflow) { + return (numeric_limits<_Size_type>::max)(); + } else { + return _Result; + } + } + + template + inline constexpr auto _Compile_time_max_size> = + _Cartesian_product_view_compile_time_max_size<_Rngs...>(); + + template + inline constexpr auto _Compile_time_max_size> = + _Cartesian_product_view_compile_time_max_size(); +#endif // _HAS_CXX23 + namespace views { class _Cartesian_product_fn { public: diff --git a/stl/inc/regex b/stl/inc/regex index bb831fa32c2..a370a56c0b9 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1486,8 +1486,8 @@ struct _Loop_vals_t { // storage for loop administration class _Node_rep : public _Node_base { // node that marks the beginning of a repetition public: - _Node_rep(bool _Greedy, int _Mn, int _Mx, _Node_end_rep* _End, unsigned int _Number) - : _Node_base(_N_rep, _Greedy ? _Fl_greedy : _Fl_none), _Min(_Mn), _Max(_Mx), _End_rep(_End), + _Node_rep(bool _Greedy, int _Min_, int _Max_, _Node_end_rep* _End, unsigned int _Number) + : _Node_base(_N_rep, _Greedy ? _Fl_greedy : _Fl_none), _Min(_Min_), _Max(_Max_), _End_rep(_End), _Loop_number(_Number), _Simple_loop(-1) {} const int _Min; diff --git a/stl/inc/stop_token b/stl/inc/stop_token index 3d65a48ddc6..ee14cc886a9 100644 --- a/stl/inc/stop_token +++ b/stl/inc/stop_token @@ -255,7 +255,7 @@ void _Stop_callback_base::_Do_attach( // fast path check if the state is already known auto _Local_sources = _State->_Stop_sources.load(); - if ((_Local_sources& uint32_t{1}) != 0) { + if ((_Local_sources & uint32_t{1}) != 0) { // stop already requested _Fn(this); return; @@ -269,7 +269,7 @@ void _Stop_callback_base::_Do_attach( auto _Head = _State->_Callbacks._Lock_and_load(); // recheck the state in case it changed while we were waiting to acquire the lock _Local_sources = _State->_Stop_sources.load(); - if ((_Local_sources& uint32_t{1}) != 0) { + if ((_Local_sources & uint32_t{1}) != 0) { // stop already requested _State->_Callbacks._Store_and_unlock(_Head); _Fn(this); diff --git a/stl/inc/tuple b/stl/inc/tuple index 6a04b92fd56..8059fbaed02 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -191,8 +191,8 @@ inline constexpr bool _Can_construct_values_from_tuple_like_v, template concept _Can_construct_from_tuple_like = _Different_from<_TupleLike, _Tuple> && _Tuple_like<_TupleLike> && !_Is_subrange_v> - && (tuple_size_v<_Tuple> - == tuple_size_v>) &&_Can_construct_values_from_tuple_like_v<_Tuple, _TupleLike> + && (tuple_size_v<_Tuple> == tuple_size_v>) // + &&_Can_construct_values_from_tuple_like_v<_Tuple, _TupleLike> && (tuple_size_v<_Tuple> != 1 || (!is_convertible_v<_TupleLike, tuple_element_t<0, _Tuple>> && !is_constructible_v, _TupleLike>) ); diff --git a/stl/inc/type_traits b/stl/inc/type_traits index e36e2e587b7..529563cccd2 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -732,8 +732,7 @@ struct has_unique_object_representations : bool_constant<__has_unique_object_rep _EXPORT_STD template _INLINE_VAR constexpr bool has_unique_object_representations_v = __has_unique_object_representations(_Ty); -// TRANSITION, VSO-1690654 -#ifdef __EDG__ +#ifdef __EDG__ // TRANSITION, VSO-1690654 template struct _Is_aggregate_impl : bool_constant<__is_aggregate(_Ty)> {}; @@ -1934,7 +1933,6 @@ inline constexpr bool is_nothrow_invocable_r_v = #endif // _HAS_CXX17 #if _HAS_CXX20 -#ifndef __EDG__ // TRANSITION, VSO-1268984 #ifndef __clang__ // TRANSITION, LLVM-48860 _EXPORT_STD template struct is_layout_compatible : bool_constant<__is_layout_compatible(_Ty1, _Ty2)> {}; @@ -1958,7 +1956,6 @@ _NODISCARD constexpr bool is_corresponding_member(_MemberTy1 _ClassTy1::*_Pm1, _ return __is_corresponding_member(_ClassTy1, _ClassTy2, _Pm1, _Pm2); } #endif // __clang__ -#endif // __EDG__ #endif // _HAS_CXX20 template diff --git a/stl/inc/variant b/stl/inc/variant index 3808ea86bc4..2dc66b9b87c 100644 --- a/stl/inc/variant +++ b/stl/inc/variant @@ -1110,11 +1110,7 @@ public: [this, &_That, _My_ref](auto _That_ref) noexcept( conjunction_v..., is_nothrow_swappable<_Types>...>) { constexpr size_t _That_idx = decltype(_That_ref)::_Idx; -#ifdef __EDG__ // TRANSITION, VSO-657455 - constexpr size_t _My_idx = decltype(_My_ref)::_Idx + 0 * _That_idx; -#else // ^^^ workaround / no workaround vvv - constexpr size_t _My_idx = decltype(_My_ref)::_Idx; -#endif // TRANSITION, VSO-657455 + constexpr size_t _My_idx = decltype(_My_ref)::_Idx; if constexpr (_My_idx == _That_idx) { // Same alternatives... if constexpr (_My_idx != variant_npos) { // ...and not valueless, swap directly using _STD swap; @@ -1127,12 +1123,7 @@ public: _That._Emplace_valueless<_My_idx>(_STD move(_My_ref._Val)); this->template _Reset<_My_idx>(); } else { // different non-valueless alternatives -#ifdef __EDG__ // TRANSITION, VSO-657455 - using _Workaround = enable_if_t<_That_idx != variant_npos, decltype(_My_ref._Val)>; - auto _Tmp = _STD move(static_cast<_Workaround>(_My_ref._Val)); -#else // ^^^ workaround / no workaround vvv auto _Tmp = _STD move(_My_ref._Val); -#endif // TRANSITION, VSO-657455 this->template _Reset<_My_idx>(); this->_Emplace_valueless<_That_idx>(_STD move(_That_ref._Val)); _That.template _Reset<_That_idx>(); diff --git a/stl/inc/xlocale b/stl/inc/xlocale index 5a70bb2cb44..1a043c4c340 100644 --- a/stl/inc/xlocale +++ b/stl/inc/xlocale @@ -144,7 +144,7 @@ public: _Atomic_counter_t _Myrefs; // the reference count protected: - explicit __CLR_OR_THIS_CALL facet(size_t _Initrefs = 0) + explicit __CLR_OR_THIS_CALL facet(size_t _Initrefs = 0) noexcept // strengthened : _Myrefs(static_cast<_Atomic_counter_t>(_Initrefs)) // non-atomic initialization {} @@ -280,6 +280,7 @@ public: locale(const locale& _Loc, const locale& _Other, category _Cat) : _Ptr(_Locimp::_New_Locimp(*_Loc._Ptr)) { // construct a locale by copying named facets if (_Cat != none) { // worth adding, do it + _STL_ASSERT((_Cat & all) == _Cat, "the bitmask value specifying category must be valid"); _Facet_guard _Guard{_Ptr}; _BEGIN_LOCINFO(_Lobj) _Locimp::_Makeloc(_Lobj, _Cat, _Ptr, &_Other); @@ -294,6 +295,7 @@ public: private: void _Construct(const string& _Str, category _Cat) { + _STL_ASSERT((_Cat & all) == _Cat, "the bitmask value specifying category must be valid"); // construct a locale with named facets bool _Bad = false; _Init(); @@ -618,7 +620,9 @@ inline unsigned short* __CRTDECL _Maklocstr(const char* _Ptr, unsigned short*, c } #endif // defined(_NATIVE_WCHAR_T_DEFINED) && !_ENFORCE_FACET_SPECIALIZATIONS -_EXPORT_STD extern "C++" class _CRTIMP2_PURE_IMPORT codecvt_base : public locale::facet { // base class for codecvt +_EXPORT_STD extern "C++" class _CRTIMP2_PURE_IMPORT codecvt_base // base class for codecvt + : public locale::facet // TRANSITION, ABI, shouldn't be derived from locale::facet +{ public: enum { // constants for different parse states ok, @@ -628,7 +632,8 @@ public: }; using result = int; - __CLR_OR_THIS_CALL codecvt_base(size_t _Refs = 0) : locale::facet(_Refs) {} + __CLR_OR_THIS_CALL codecvt_base(size_t _Refs = 0) noexcept // strengthened + : locale::facet(_Refs) {} bool __CLR_OR_THIS_CALL always_noconv() const noexcept { // return true if conversions never change input (from codecvt) @@ -2361,7 +2366,9 @@ protected: #define _UP _UPPER // 'A'-'Z' #define _XD _HEX // '0'-'9', 'A'-'F', 'a'-'f' -_EXPORT_STD extern "C++" struct _CRTIMP2_PURE_IMPORT ctype_base : locale::facet { // base for ctype +_EXPORT_STD extern "C++" struct _CRTIMP2_PURE_IMPORT ctype_base // base for ctype + : locale::facet // TRANSITION, ABI, shouldn't be derived from locale::facet +{ enum { // constants for character classifications alnum = _DI | _LO | _UP | _XA, alpha = _LO | _UP | _XA, @@ -2378,7 +2385,8 @@ _EXPORT_STD extern "C++" struct _CRTIMP2_PURE_IMPORT ctype_base : locale::facet }; using mask = short; // to match - __CLR_OR_THIS_CALL ctype_base(size_t _Refs = 0) : locale::facet(_Refs) {} + __CLR_OR_THIS_CALL ctype_base(size_t _Refs = 0) noexcept // strengthened + : locale::facet(_Refs) {} __CLR_OR_THIS_CALL ~ctype_base() noexcept override {} }; diff --git a/stl/inc/xlocmes b/stl/inc/xlocmes index 171bea273fd..ca9355f1d94 100644 --- a/stl/inc/xlocmes +++ b/stl/inc/xlocmes @@ -18,10 +18,14 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN -_EXPORT_STD struct messages_base : locale::facet { // base class for messages +_EXPORT_STD struct messages_base // base class for messages + : locale::facet // TRANSITION, ABI, shouldn't be derived from locale::facet +{ using catalog = int; - explicit messages_base(size_t _Refs = 0) : locale::facet(_Refs) {} + messages_base() noexcept // strengthened + : messages_base(0) {} + explicit messages_base(size_t _Refs) noexcept : locale::facet(_Refs) {} }; _EXPORT_STD template diff --git a/stl/inc/xlocmon b/stl/inc/xlocmon index a8c1eafabde..7fb534b852c 100644 --- a/stl/inc/xlocmon +++ b/stl/inc/xlocmon @@ -19,7 +19,9 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN -_EXPORT_STD struct money_base : locale::facet { // ultimate base class for moneypunct +_EXPORT_STD struct money_base // ultimate base class for moneypunct + : locale::facet // TRANSITION, ABI, shouldn't be derived from locale::facet +{ enum { // constants for different format codes symbol = '$', sign = '+', @@ -33,7 +35,8 @@ _EXPORT_STD struct money_base : locale::facet { // ultimate base class for money char field[4]; }; - money_base(size_t _Refs = 0) : locale::facet(_Refs) {} + money_base(size_t _Refs = 0) noexcept // strengthened + : locale::facet(_Refs) {} }; template diff --git a/stl/inc/xlocnum b/stl/inc/xlocnum index 47a0b964ee1..a14c070a63e 100644 --- a/stl/inc/xlocnum +++ b/stl/inc/xlocnum @@ -1376,7 +1376,7 @@ protected: const auto _Ngen = static_cast(_CSTD sprintf_s( &_Buf[0], _Buf.size(), _Ffmt(_Fmt, 0, _Iosbase.flags()), static_cast(_Precision), _Val)); - return _Fput(_Dest, _Iosbase, _Fill, _Buf.c_str(), _Ngen); + return _Fput_v2(_Dest, _Iosbase, _Fill, _Buf.c_str(), _Ngen, (_STD isnan)(_Val)); } virtual _OutIt __CLR_OR_THIS_CALL do_put( @@ -1400,7 +1400,7 @@ protected: const auto _Ngen = static_cast(_CSTD sprintf_s( &_Buf[0], _Buf.size(), _Ffmt(_Fmt, 'L', _Iosbase.flags()), static_cast(_Precision), _Val)); - return _Fput(_Dest, _Iosbase, _Fill, _Buf.c_str(), _Ngen); + return _Fput_v2(_Dest, _Iosbase, _Fill, _Buf.c_str(), _Ngen, (_STD isnan)(_Val)); } #pragma warning(pop) @@ -1462,7 +1462,13 @@ private: } _OutIt __CLRCALL_OR_CDECL _Fput(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const char* _Buf, - size_t _Count) const { // put formatted floating-point to _Dest + size_t _Count) const { // TRANSITION, ABI: preserved for binary compatibility + return _Fput_v2(_Dest, _Iosbase, _Fill, _Buf, _Count, false); + } + + template // TRANSITION, ABI + _OutIt _Fput_v2(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const char* _Buf, size_t _Count, + bool _Is_nan_val) const { // put formatted floating-point to _Dest auto _Prefix = static_cast(0 < _Count && (*_Buf == '+' || *_Buf == '-')); const char* _Exps; if ((_Iosbase.flags() & ios_base::floatfield) != ios_base::hexfloat) { @@ -1491,13 +1497,15 @@ private: _Groupstring[_Poff] = _Punct_fac.decimal_point(); } - size_t _Off = _Poff == _Count ? _Eoff : _Poff; - const char* _Pg = &_Grouping[0]; - while (*_Pg != CHAR_MAX && '\0' < *_Pg && static_cast(*_Pg) < _Off - _Prefix) { - // add thousands separator - _Groupstring.insert(_Off -= *_Pg, 1, _Kseparator); - if ('\0' < _Pg[1]) { - ++_Pg; // not last group, advance + if (!_Is_nan_val) { + size_t _Off = _Poff == _Count ? _Eoff : _Poff; + const char* _Pg = &_Grouping[0]; + while (*_Pg != CHAR_MAX && '\0' < *_Pg && static_cast(*_Pg) < _Off - _Prefix) { + // add thousands separator + _Groupstring.insert(_Off -= *_Pg, 1, _Kseparator); + if ('\0' < _Pg[1]) { + ++_Pg; // not last group, advance + } } } diff --git a/stl/inc/xloctime b/stl/inc/xloctime index 722feeb3303..8b30b8493e3 100644 --- a/stl/inc/xloctime +++ b/stl/inc/xloctime @@ -86,7 +86,9 @@ ios_base::iostate _Getint_v2(_InIt& _First, _InIt& _Last, int _Lo, int _Hi, int& return _State; } -_EXPORT_STD extern "C++" struct _CRTIMP2_PURE_IMPORT time_base : locale::facet { // base class for time_get +_EXPORT_STD extern "C++" struct _CRTIMP2_PURE_IMPORT time_base // base class for time_get + : locale::facet // TRANSITION, ABI, shouldn't be derived from locale::facet +{ enum dateorder { // constants for different orders of date components no_order, dmy, @@ -95,7 +97,8 @@ _EXPORT_STD extern "C++" struct _CRTIMP2_PURE_IMPORT time_base : locale::facet { ydm }; - __CLR_OR_THIS_CALL time_base(size_t _Refs = 0) : locale::facet(_Refs) {} + __CLR_OR_THIS_CALL time_base(size_t _Refs = 0) noexcept // strengthened + : locale::facet(_Refs) {} __CLR_OR_THIS_CALL ~time_base() noexcept override {} }; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index c2c73ef5906..0260da13c88 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -2174,16 +2174,34 @@ _NODISCARD constexpr bool _Allocators_equal(const _Alloc& _Lhs, const _Alloc& _R } } +#if _HAS_CXX23 +template +inline constexpr bool _Has_member_from_primary = false; +template +inline constexpr bool _Has_member_from_primary<_Ty, void_t> = true; + +// Avoid using allocate_at_least when the allocator publicly derives from std::allocator: +// "old" allocators might hide allocate and deallocate but fail to hide allocate_at_least. +// Also avoid using allocate_at_least from std::allocator itself because it currently doesn't do anything useful. +template +inline constexpr bool _Should_allocate_at_least = + !_Has_member_from_primary<_Alloc> + && _Has_member_allocate_at_least<_Alloc, typename allocator_traits<_Alloc>::size_type>; +#endif // _HAS_CXX23 + template _NODISCARD_RAW_PTR_ALLOC _CONSTEXPR20 typename allocator_traits<_Alloc>::pointer _Allocate_at_least_helper( _Alloc& _Al, _CRT_GUARDOVERFLOW typename allocator_traits<_Alloc>::size_type& _Count) { #if _HAS_CXX23 - auto [_Ptr, _Allocated] = allocator_traits<_Alloc>::allocate_at_least(_Al, _Count); - _Count = _Allocated; - return _Ptr; -#else // _HAS_CXX23 - return _Al.allocate(_Count); + if constexpr (_Should_allocate_at_least<_Alloc>) { + auto [_Ptr, _Allocated] = _Al.allocate_at_least(_Count); + _Count = _Allocated; + return _Ptr; + } else #endif // _HAS_CXX23 + { + return _Al.allocate(_Count); + } } _EXPORT_STD template diff --git a/stl/inc/xtree b/stl/inc/xtree index aec01557a7e..767027093f1 100644 --- a/stl/inc/xtree +++ b/stl/inc/xtree @@ -907,25 +907,18 @@ public: _Swap_val_excluding_comp(_Right); } -private: - void _Different_allocator_move_construct(_Tree&& _Right) { - // TRANSITION, VSO-761321 (inline into only caller when that is fixed) - auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alnode, _Getal()); - const auto _Scary = _Get_scary(); - _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, *_Scary); - _Tree_head_scoped_ptr<_Alnode, _Scary_val> _Sentinel(_Getal(), *_Scary); - _Copy<_Strategy::_Move>(_Right); - _Sentinel._Release(); - _Proxy._Release(); - } - -public: _Tree(_Tree&& _Right, const allocator_type& _Al) : _Mypair(_One_then_variadic_args_t{}, _Right.key_comp(), // intentionally copy comparator, see LWG-2227 _One_then_variadic_args_t{}, _Al) { if constexpr (!_Alnode_traits::is_always_equal::value) { if (_Getal() != _Right._Getal()) { - _Different_allocator_move_construct(_STD move(_Right)); + auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alnode, _Getal()); + const auto _Scary = _Get_scary(); + _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, *_Scary); + _Tree_head_scoped_ptr<_Alnode, _Scary_val> _Sentinel(_Getal(), *_Scary); + _Copy<_Strategy::_Move>(_Right); + _Sentinel._Release(); + _Proxy._Release(); return; } } diff --git a/stl/inc/xutility b/stl/inc/xutility index 0e7933c44ad..a4312e1ba25 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -14,10 +14,6 @@ #include #include -#if _HAS_CXX23 -#include -#endif // _HAS_CXX23 - #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) @@ -868,22 +864,40 @@ _EXPORT_STD template requires (indirectly_readable<_Its> && ...) && invocable<_Fn, iter_reference_t<_Its>...> using indirect_result_t = invoke_result_t<_Fn, iter_reference_t<_Its>...>; -_EXPORT_STD template _Proj> -struct projected { - using value_type = remove_cvref_t>; - indirect_result_t<_Proj&, _It> operator*() const { - _CSTD abort(); - } +template +struct _Projected_difference_type_impl { + struct _Base {}; +}; + +template +struct _Projected_difference_type_impl<_It> { + struct _Base { + using difference_type = iter_difference_t<_It>; + }; }; template -struct _Indirect_value_impl> { - using type = invoke_result_t<_Proj&, _Indirect_value_t<_It>>; +struct _Projected_impl { + struct _Type : _Projected_difference_type_impl<_It>::_Base { + using _Iterator = _It; + using _Projection = _Proj; + + using value_type = remove_cvref_t>; + indirect_result_t<_Proj&, _It> operator*() const { + _CSTD abort(); + } + }; }; -template -struct incrementable_traits> { - using difference_type = iter_difference_t<_It>; +_EXPORT_STD template _Proj> +using projected = _Projected_impl<_It, _Proj>::_Type; + +template +concept _Projected_specialization = same_as<_Ty, projected>; + +template <_Projected_specialization _ProjTy> +struct _Indirect_value_impl<_ProjTy> { + using type = invoke_result_t>; }; _EXPORT_STD template @@ -7179,7 +7193,9 @@ _NODISCARD constexpr bool _Mul_overflow(const _Int _Left, const _Int _Right, _In #endif // __clang__ { if constexpr (!_Signed_integer_like<_Int>) { - const bool _Overflow = _Left != 0 && _Right > (numeric_limits<_Int>::max)() / _Left; + // use instead of numeric_limits::max; avoid dependency + constexpr auto _UInt_max = static_cast<_Int>(-1); + const bool _Overflow = _Left != 0 && _Right > _UInt_max / _Left; if (!_Overflow) { _Out = static_cast<_Int>(_Left * _Right); } @@ -7207,10 +7223,12 @@ _NODISCARD constexpr bool _Mul_overflow(const _Int _Left, const _Int _Right, _In return false; } + // use instead of numeric_limits::max; avoid dependency + constexpr auto _Int_max = static_cast<_UInt>(static_cast<_UInt>(-1) / 2); if (_Negative) { - return _ULeft > (static_cast<_UInt>((numeric_limits<_Int>::max)()) + _UInt{1}) / _URight; + return _ULeft > (_Int_max + _UInt{1}) / _URight; } else { - return _ULeft > static_cast<_UInt>((numeric_limits<_Int>::max)()) / _URight; + return _ULeft > _Int_max / _URight; } // ^^^ Based on llvm::MulOverflow ^^^ } diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 761d5e2291d..d9901ab61ea 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -72,6 +72,12 @@ // P1164R1 Making create_directory() Intuitive // P1165R1 Consistently Propagating Stateful Allocators In basic_string's operator+() // P1902R1 Missing Feature-Test Macros 2017-2019 +// P2013R5 Freestanding Language: Optional ::operator new +// (no change is needed for our hosted implementation) +// P2198R7 Freestanding Feature-Test Macros And Implementation-Defined Extensions +// (except for __cpp_lib_freestanding_ranges) +// P2338R4 Freestanding Library: Character Primitives And The C Library +// (except for __cpp_lib_freestanding_charconv) // P2401R0 Conditional noexcept For exchange() // _HAS_CXX17 directly controls: @@ -127,6 +133,8 @@ // P2162R2 Inheriting From variant // P2251R1 Require span And basic_string_view To Be Trivially Copyable // (basic_string_view always provides this behavior) +// P2338R4 Freestanding Library: Character Primitives And The C Library +// (including __cpp_lib_freestanding_charconv) // P2517R1 Conditional noexcept For apply() // _HAS_CXX17 indirectly controls: @@ -266,6 +274,8 @@ // P2106R0 Range Algorithm Result Types // P2116R0 Removing tuple-Like Protocol Support From Fixed-Extent span // P2167R3 Improving boolean-testable Usage +// P2198R7 Freestanding Feature-Test Macros And Implementation-Defined Extensions +// (including __cpp_lib_freestanding_ranges) // P2210R2 Superior String Splitting // P2216R3 std::format Improvements // P2231R1 Completing constexpr In optional And variant @@ -285,6 +295,7 @@ // P2432R1 Fix istream_view // P2508R1 basic_format_string, format_string, wformat_string // P2520R0 move_iterator Should Be A Random-Access Iterator +// P2538R1 ADL-Proof projected // P2572R1 std::format Fill Character Allowances // P2588R3 barrier's Phase Completion Guarantees // P2602R2 Poison Pills Are Too Toxic @@ -526,6 +537,20 @@ #define _FALLTHROUGH #endif +#ifndef __has_cpp_attribute // vvv no attributes vvv +#define _LIKELY +#define _UNLIKELY +#elif __has_cpp_attribute(likely) >= 201803L && __has_cpp_attribute(unlikely) >= 201803L // ^^^ no attr / C++20 attr vvv +#define _LIKELY [[likely]] +#define _UNLIKELY [[unlikely]] +#elif defined(__clang__) // ^^^ C++20 attributes / clang attributes and C++17 or C++14 vvv +#define _LIKELY [[__likely__]] +#define _UNLIKELY [[__unlikely__]] +#else // ^^^ clang attributes and C++17 or C++14 / C1XX attributes and C++17 or C++14 vvv +#define _LIKELY +#define _UNLIKELY +#endif // ^^^ C1XX attributes and C++17 or C++14 ^^^ + // _HAS_NODISCARD (in vcruntime.h) controls: // [[nodiscard]] attributes on STL functions @@ -664,10 +689,12 @@ #pragma push_macro("known_semantics") #pragma push_macro("noop_dtor") #pragma push_macro("intrinsic") +#pragma push_macro("lifetimebound") #undef msvc #undef known_semantics #undef noop_dtor #undef intrinsic +#undef lifetimebound #ifndef __has_cpp_attribute #define _HAS_MSVC_ATTRIBUTE(x) 0 @@ -701,7 +728,19 @@ #define _MSVC_INTRINSIC #endif +// Should we enable [[msvc::lifetimebound]] or [[clang::lifetimebound]] warnings? +#if !defined(__has_cpp_attribute) || defined(_SILENCE_LIFETIMEBOUND_WARNING) +#define _MSVC_LIFETIMEBOUND +#elif _HAS_MSVC_ATTRIBUTE(lifetimebound) +#define _MSVC_LIFETIMEBOUND [[msvc::lifetimebound]] +#elif __has_cpp_attribute(_Clang::__lifetimebound__) +#define _MSVC_LIFETIMEBOUND [[_Clang::__lifetimebound__]] +#else +#define _MSVC_LIFETIMEBOUND +#endif + #undef _HAS_MSVC_ATTRIBUTE +#pragma pop_macro("lifetimebound") #pragma pop_macro("intrinsic") #pragma pop_macro("noop_dtor") #pragma pop_macro("known_semantics") @@ -834,7 +873,7 @@ #define _CPPLIB_VER 650 #define _MSVC_STL_VERSION 143 -#define _MSVC_STL_UPDATE 202306L +#define _MSVC_STL_UPDATE 202307L #ifndef _ALLOW_COMPILER_AND_STL_VERSION_MISMATCH #if defined(__CUDACC__) && defined(__CUDACC_VER_MAJOR__) @@ -1446,7 +1485,19 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define _CXX23_DEPRECATE_DENORM #endif // ^^^ warning disabled ^^^ -// next warning number: STL4043 +#if _HAS_CXX17 && !defined(_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING) \ + && !defined(_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS) +#define _DEPRECATE_STDEXT_ARR_ITERS \ + [[deprecated( \ + "warning STL4043: stdext::checked_array_iterator, stdext::unchecked_array_iterator, and related factory " \ + "functions are non-Standard extensions and will be removed in the future. std::span (since C++20) " \ + "and gsl::span can be used instead. You can define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING or " \ + "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to suppress this warning.")]] +#else // ^^^ warning enabled / warning disabled vvv +#define _DEPRECATE_STDEXT_ARR_ITERS +#endif // ^^^ warning disabled ^^^ + +// next warning number: STL4044 // next error number: STL1006 @@ -1523,20 +1574,33 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #endif // _HAS_GARBAGE_COLLECTION_SUPPORT_DELETED_IN_CXX23 // C++14 -#define __cpp_lib_chrono_udls 201304L -#define __cpp_lib_complex_udls 201309L -#define __cpp_lib_exchange_function 201304L -#define __cpp_lib_generic_associative_lookup 201304L -#define __cpp_lib_integer_sequence 201304L -#define __cpp_lib_integral_constant_callable 201304L -#define __cpp_lib_is_final 201402L -#define __cpp_lib_is_null_pointer 201309L -#define __cpp_lib_make_reverse_iterator 201402L -#define __cpp_lib_make_unique 201304L -#define __cpp_lib_null_iterators 201304L -#define __cpp_lib_quoted_string_io 201304L -#define __cpp_lib_result_of_sfinae 201210L -#define __cpp_lib_robust_nonmodifying_seq_ops 201304L +#define __cpp_lib_chrono_udls 201304L +#define __cpp_lib_complex_udls 201309L +#define __cpp_lib_exchange_function 201304L +#define __cpp_lib_freestanding_char_traits 202306L +#define __cpp_lib_freestanding_cstdlib 202306L +#define __cpp_lib_freestanding_cstring 202306L +#define __cpp_lib_freestanding_cwchar 202306L +#define __cpp_lib_freestanding_errc 202306L +#define __cpp_lib_freestanding_feature_test_macros 202306L +#define __cpp_lib_freestanding_functional 202306L +#define __cpp_lib_freestanding_iterator 202306L +#define __cpp_lib_freestanding_memory 202306L +#define __cpp_lib_freestanding_operator_new 202306L +#define __cpp_lib_freestanding_ratio 202306L +#define __cpp_lib_freestanding_tuple 202306L +#define __cpp_lib_freestanding_utility 202306L +#define __cpp_lib_generic_associative_lookup 201304L +#define __cpp_lib_integer_sequence 201304L +#define __cpp_lib_integral_constant_callable 201304L +#define __cpp_lib_is_final 201402L +#define __cpp_lib_is_null_pointer 201309L +#define __cpp_lib_make_reverse_iterator 201402L +#define __cpp_lib_make_unique 201304L +#define __cpp_lib_null_iterators 201304L +#define __cpp_lib_quoted_string_io 201304L +#define __cpp_lib_result_of_sfinae 201210L +#define __cpp_lib_robust_nonmodifying_seq_ops 201304L #ifndef _M_CEE_PURE #define __cpp_lib_shared_timed_mutex 201402L #endif // _M_CEE_PURE @@ -1575,6 +1639,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #endif // _HAS_STD_BYTE #define __cpp_lib_clamp 201603L #define __cpp_lib_filesystem 201703L +#define __cpp_lib_freestanding_charconv 202306L #define __cpp_lib_gcd_lcm 201606L #define __cpp_lib_hardware_interference_size 201703L #define __cpp_lib_has_unique_object_representations 201606L @@ -1657,7 +1722,8 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_erase_if 202002L #ifdef __cpp_lib_concepts -#define __cpp_lib_format 202207L +#define __cpp_lib_format 202207L +#define __cpp_lib_freestanding_ranges 202306L #endif // __cpp_lib_concepts #define __cpp_lib_generic_unordered_lookup 201811L @@ -1666,19 +1732,15 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_interpolate 201902L #define __cpp_lib_is_constant_evaluated 201811L -#ifndef __EDG__ // TRANSITION, VSO-1268984 #ifndef __clang__ // TRANSITION, LLVM-48860 #define __cpp_lib_is_layout_compatible 201907L #endif // __clang__ -#endif // __EDG__ #define __cpp_lib_is_nothrow_convertible 201806L -#ifndef __EDG__ // TRANSITION, VSO-1268984 #ifndef __clang__ // TRANSITION, LLVM-48860 #define __cpp_lib_is_pointer_interconvertible 201907L #endif // __clang__ -#endif // __EDG__ #define __cpp_lib_jthread 201911L #define __cpp_lib_latch 201907L diff --git a/stl/src/StlCompareStringA.cpp b/stl/src/StlCompareStringA.cpp index 281ccdec63b..81eb6e41c57 100644 --- a/stl/src/StlCompareStringA.cpp +++ b/stl/src/StlCompareStringA.cpp @@ -133,7 +133,6 @@ extern "C" int __cdecl __crtCompareStringA(_In_z_ LPCWSTR LocaleName, _In_ DWORD } // allocate enough space for chars -#pragma warning(suppress : 6386) // TRANSITION, VSO-1152705 false buffer overrun report in _malloca_crt_t const __crt_scoped_stack_ptr wbuffer2(_malloca_crt_t(wchar_t, buff_size2)); if (wbuffer2.get() == nullptr) { return 0; diff --git a/stl/src/StlLCMapStringA.cpp b/stl/src/StlLCMapStringA.cpp index d176fcc4151..2ddf8258b5d 100644 --- a/stl/src/StlLCMapStringA.cpp +++ b/stl/src/StlLCMapStringA.cpp @@ -94,7 +94,6 @@ extern "C" int __cdecl __crtLCMapStringA(_In_opt_z_ LPCWSTR LocaleName, _In_ DWO int outbuff_size = retval; // allocate enough space for wide chars (includes null terminator if any) -#pragma warning(suppress : 6386) // TRANSITION, VSO-1152705 false buffer overrun report in _malloca_crt_t const __crt_scoped_stack_ptr outwbuffer(_malloca_crt_t(wchar_t, outbuff_size)); if (!outwbuffer) { return retval; diff --git a/stl/src/cond.cpp b/stl/src/cond.cpp index e9eb1c642b7..153b59974ee 100644 --- a/stl/src/cond.cpp +++ b/stl/src/cond.cpp @@ -15,9 +15,9 @@ struct _Cnd_internal_imp_t { // condition variable implementation for ConcRT typename std::_Aligned_storage::type cv; - [[nodiscard]] Concurrency::details::stl_condition_variable_interface* _get_cv() noexcept { + [[nodiscard]] Concurrency::details::stl_condition_variable_win7* _get_cv() noexcept { // get pointer to implementation - return reinterpret_cast(&cv); + return reinterpret_cast(&cv); } }; @@ -28,9 +28,7 @@ void _Cnd_init_in_situ(const _Cnd_t cond) { // initialize condition variable in Concurrency::details::create_stl_condition_variable(cond->_get_cv()); } -void _Cnd_destroy_in_situ(const _Cnd_t cond) { // destroy condition variable in situ - cond->_get_cv()->destroy(); -} +void _Cnd_destroy_in_situ(_Cnd_t) {} // destroy condition variable in situ int _Cnd_init(_Cnd_t* const pcond) { // initialize *pcond = nullptr; @@ -53,7 +51,7 @@ void _Cnd_destroy(const _Cnd_t cond) { // clean up } int _Cnd_wait(const _Cnd_t cond, const _Mtx_t mtx) { // wait until signaled - const auto cs = static_cast(_Mtx_getconcrtcs(mtx)); + const auto cs = static_cast(_Mtx_getconcrtcs(mtx)); _Mtx_clear_owner(mtx); cond->_get_cv()->wait(cs); _Mtx_reset_owner(mtx); @@ -63,7 +61,7 @@ int _Cnd_wait(const _Cnd_t cond, const _Mtx_t mtx) { // wait until signaled // wait until signaled or timeout int _Cnd_timedwait(const _Cnd_t cond, const _Mtx_t mtx, const _timespec64* const target) { int res = _Thrd_success; - const auto cs = static_cast(_Mtx_getconcrtcs(mtx)); + const auto cs = static_cast(_Mtx_getconcrtcs(mtx)); if (target == nullptr) { // no target time specified, wait on mutex _Mtx_clear_owner(mtx); cond->_get_cv()->wait(cs); diff --git a/stl/src/cthread.cpp b/stl/src/cthread.cpp index f10d1ff6c8b..4b67c76c3af 100644 --- a/stl/src/cthread.cpp +++ b/stl/src/cthread.cpp @@ -42,7 +42,7 @@ namespace { _EXTERN_C // TRANSITION, ABI: _Thrd_exit() is preserved for binary compatibility -_CRTIMP2_PURE void _Thrd_exit(int res) { // terminate execution of calling thread +[[noreturn]] _CRTIMP2_PURE void _Thrd_exit(int res) { // terminate execution of calling thread _endthreadex(res); } diff --git a/stl/src/mutex.cpp b/stl/src/mutex.cpp index dad5b4f7655..0d117a6ca8d 100644 --- a/stl/src/mutex.cpp +++ b/stl/src/mutex.cpp @@ -13,7 +13,7 @@ #include "primitives.hpp" -extern "C" _CRTIMP2_PURE void _Thrd_abort(const char* msg) { // abort on precondition failure +extern "C" [[noreturn]] _CRTIMP2_PURE void _Thrd_abort(const char* msg) { // abort on precondition failure fputs(msg, stderr); fputc('\n', stderr); abort(); @@ -43,8 +43,8 @@ struct _Mtx_internal_imp_t { // ConcRT mutex Concurrency::details::stl_critical_section_max_alignment>::type cs; long thread_id; int count; - Concurrency::details::stl_critical_section_interface* _get_cs() { // get pointer to implementation - return reinterpret_cast(&cs); + [[nodiscard]] Concurrency::details::stl_critical_section_win7* _get_cs() { // get pointer to implementation + return reinterpret_cast(&cs); } }; @@ -65,7 +65,7 @@ void _Mtx_init_in_situ(_Mtx_t mtx, int type) { // initialize mutex in situ void _Mtx_destroy_in_situ(_Mtx_t mtx) { // destroy mutex in situ _THREAD_ASSERT(mtx->count == 0, "mutex destroyed while busy"); - mtx->_get_cs()->destroy(); + (void) mtx; } int _Mtx_init(_Mtx_t* mtx, int type) { // initialize mutex @@ -126,7 +126,7 @@ static int mtx_do_lock(_Mtx_t mtx, const _timespec64* target) { // lock mutex while (now.tv_sec < target->tv_sec || now.tv_sec == target->tv_sec && now.tv_nsec < target->tv_nsec) { // time has not expired if (mtx->thread_id == static_cast(GetCurrentThreadId()) - || mtx->_get_cs()->try_lock_for(_Xtime_diff_to_millis2(target, &now))) { // stop waiting + || mtx->_get_cs()->try_lock()) { // stop waiting res = WAIT_OBJECT_0; break; } else { diff --git a/stl/src/ppltasks.cpp b/stl/src/ppltasks.cpp index 1108413976a..147427ef05b 100644 --- a/stl/src/ppltasks.cpp +++ b/stl/src/ppltasks.cpp @@ -35,7 +35,7 @@ extern "C" NTSYSAPI _Success_(return != 0) WORD NTAPI namespace Concurrency { namespace details { - _CRTIMP2 void __cdecl _ReportUnobservedException() { + [[noreturn]] _CRTIMP2 void __cdecl _ReportUnobservedException() { #if (defined(_M_IX86) || defined(_M_X64)) && !defined(_CRT_APP) if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE)) diff --git a/stl/src/primitives.hpp b/stl/src/primitives.hpp index a61e7755474..b3d2db32367 100644 --- a/stl/src/primitives.hpp +++ b/stl/src/primitives.hpp @@ -10,25 +10,7 @@ namespace Concurrency { namespace details { - class __declspec(novtable) stl_critical_section_interface { - public: - virtual void lock() = 0; - virtual bool try_lock() = 0; - virtual bool try_lock_for(unsigned int) = 0; - virtual void unlock() = 0; - virtual void destroy() = 0; - }; - - class __declspec(novtable) stl_condition_variable_interface { - public: - virtual void wait(stl_critical_section_interface*) = 0; - virtual bool wait_for(stl_critical_section_interface*, unsigned int) = 0; - virtual void notify_one() = 0; - virtual void notify_all() = 0; - virtual void destroy() = 0; - }; - - class stl_critical_section_win7 final : public stl_critical_section_interface { + class stl_critical_section_win7 { public: stl_critical_section_win7() = default; @@ -36,22 +18,15 @@ namespace Concurrency { stl_critical_section_win7(const stl_critical_section_win7&) = delete; stl_critical_section_win7& operator=(const stl_critical_section_win7&) = delete; - void destroy() override {} - - void lock() override { + void lock() { AcquireSRWLockExclusive(&m_srw_lock); } - bool try_lock() override { + bool try_lock() { return TryAcquireSRWLockExclusive(&m_srw_lock) != 0; } - bool try_lock_for(unsigned int) override { - // STL will call try_lock_for once again if this call will not succeed - return stl_critical_section_win7::try_lock(); - } - - void unlock() override { + void unlock() { _Analysis_assume_lock_held_(m_srw_lock); ReleaseSRWLockExclusive(&m_srw_lock); } @@ -61,50 +36,46 @@ namespace Concurrency { } private: + void* unused = nullptr; // TRANSITION, ABI: was the vptr SRWLOCK m_srw_lock = SRWLOCK_INIT; }; - class stl_condition_variable_win7 final : public stl_condition_variable_interface { + class stl_condition_variable_win7 { public: - stl_condition_variable_win7() { - InitializeConditionVariable(&m_condition_variable); - } + stl_condition_variable_win7() = default; ~stl_condition_variable_win7() = delete; stl_condition_variable_win7(const stl_condition_variable_win7&) = delete; stl_condition_variable_win7& operator=(const stl_condition_variable_win7&) = delete; - void destroy() override {} - - void wait(stl_critical_section_interface* lock) override { - if (!stl_condition_variable_win7::wait_for(lock, INFINITE)) { + void wait(stl_critical_section_win7* lock) { + if (!wait_for(lock, INFINITE)) { std::terminate(); } } - bool wait_for(stl_critical_section_interface* lock, unsigned int timeout) override { - return SleepConditionVariableSRW(&m_condition_variable, - static_cast(lock)->native_handle(), timeout, 0) - != 0; + bool wait_for(stl_critical_section_win7* lock, unsigned int timeout) { + return SleepConditionVariableSRW(&m_condition_variable, lock->native_handle(), timeout, 0) != 0; } - void notify_one() override { + void notify_one() { WakeConditionVariable(&m_condition_variable); } - void notify_all() override { + void notify_all() { WakeAllConditionVariable(&m_condition_variable); } private: - CONDITION_VARIABLE m_condition_variable; + void* unused = nullptr; // TRANSITION, ABI: was the vptr + CONDITION_VARIABLE m_condition_variable = CONDITION_VARIABLE_INIT; }; - inline void create_stl_critical_section(stl_critical_section_interface* p) { + inline void create_stl_critical_section(stl_critical_section_win7* p) { new (p) stl_critical_section_win7; } - inline void create_stl_condition_variable(stl_condition_variable_interface* p) { + inline void create_stl_condition_variable(stl_condition_variable_win7* p) { new (p) stl_condition_variable_win7; } diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 4c39a78d079..224f1ffecac 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -155,7 +155,7 @@ std/utilities/memory/specialized.algorithms/uninitialized.fill.n/ranges_uninitia std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp FAIL std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp FAIL -# libc++ doesn't speculatively implement LWG-3940 +# libc++ doesn't implement LWG-3940 std/utilities/expected/expected.void/observers/value.pass.cpp FAIL # libc++ doesn't implement P1957R2 "Converting from `T*` to `bool` should be considered narrowing" @@ -417,7 +417,7 @@ std/utilities/function.objects/func.wrap/func.wrap.func/noncopyable_return_type. # *** 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:1 SKIPPED +std/depr/depr.c.headers/tgmath_h.pass.cpp:1 FAIL # *** CLANG ISSUES, NOT YET ANALYZED *** @@ -513,8 +513,8 @@ std/thread/thread.threads/thread.thread.class/thread.thread.assign/move2.pass.cp std/thread/thread.threads/thread.thread.class/thread.thread.member/join.pass.cpp SKIPPED # OS-29877133 "LDBL_DECIMAL_DIG missing from " -std/depr/depr.c.headers/float_h.pass.cpp FAIL -std/language.support/support.limits/c.limits/cfloat.pass.cpp FAIL +std/depr/depr.c.headers/float_h.pass.cpp:0 FAIL +std/language.support/support.limits/c.limits/cfloat.pass.cpp:0 FAIL # *** LIKELY BOGUS TESTS *** @@ -667,6 +667,9 @@ std/utilities/format/format.formatter/format.formatter.spec/formatter.unsigned_i std/utilities/format/format.formatter/format.formatter.spec/formatter.char.pass.cpp FAIL std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp FAIL +# libc++ requires bind_front to be SFINAE-friendly, although the Standard uses "Mandates:" for constructibility. +std/utilities/function.objects/func.bind_front/bind_front.pass.cpp FAIL + # libc++ chose option A for [time.clock.file.members], and we chose option B. std/time/time.clock/time.clock.file/to_from_sys.pass.cpp FAIL @@ -680,8 +683,9 @@ std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get std/containers/sequences/vector/vector.cons/assign_copy.pass.cpp FAIL # LIT's ADDITIONAL_COMPILE_FLAGS is problematic -std/utilities/meta/meta.unary/dependent_return_type.compile.pass.cpp SKIPPED +std/concepts/concepts.lang/concept.default.init/default_initializable.compile.pass.cpp:0 FAIL std/utilities/format/format.functions/escaped_output.ascii.pass.cpp SKIPPED +std/utilities/meta/meta.unary/dependent_return_type.compile.pass.cpp SKIPPED std/utilities/variant/variant.variant/implicit_ctad.pass.cpp SKIPPED # libc++ speculatively implements LWG-3645 @@ -713,6 +717,9 @@ std/time/time.syn/formatter.year_month_weekday.pass.cpp:0 FAIL std/thread/thread.mutex/thread.lock/thread.lock.scoped/mutex.pass.cpp FAIL std/thread/thread.mutex/thread.mutex.requirements/thread.shared_mutex.requirements/thread.shared_mutex.class/default.pass.cpp:1 FAIL +# This test assumes that array is not const-default-constructible. +std/concepts/concepts.lang/concept.default.init/default_initializable.compile.pass.cpp:1 FAIL + # *** LIKELY STL BUGS *** # Not analyzed, likely STL bugs. Various assertions. @@ -819,9 +826,6 @@ std/localization/locale.categories/category.ctype/locale.codecvt/locale.codecvt. std/utilities/format/format.formatter/format.parse.ctx/next_arg_id.pass.cpp FAIL std/time/time.syn/formatter.month_day_last.pass.cpp FAIL -# Likely STL bug in `bind_front`: we don't respect deletion of the target call operator -std/utilities/function.objects/func.bind_front/bind_front.pass.cpp FAIL - # Likely STL bug in `join_view::_Iterator`: constexpr weirdness std/ranges/range.adaptors/range.join.view/end.pass.cpp:1 FAIL std/ranges/range.adaptors/range.join.view/iterator/decrement.pass.cpp:0 FAIL @@ -978,7 +982,6 @@ std/algorithms/algorithms.results/in_found_result.pass.cpp:0 FAIL std/algorithms/algorithms.results/min_max_result.pass.cpp:0 FAIL std/algorithms/ranges_robust_against_dangling.pass.cpp FAIL std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp FAIL -std/concepts/concepts.lang/concept.default.init/default_initializable.compile.pass.cpp:0 FAIL std/containers/sequences/deque/abi.compile.pass.cpp FAIL std/containers/sequences/vector.bool/construct_iter_iter.pass.cpp:0 FAIL std/containers/sequences/vector.bool/construct_iter_iter_alloc.pass.cpp:0 FAIL @@ -1062,11 +1065,7 @@ std/ranges/range.adaptors/range.take/adaptor.pass.cpp FAIL std/ranges/range.factories/range.single.view/cpo.pass.cpp FAIL std/thread/futures/futures.task/futures.task.members/ctor2.compile.pass.cpp FAIL std/utilities/format/format.functions/escaped_output.ascii.pass.cpp FAIL -std/utilities/format/format.functions/format.locale.pass.cpp FAIL -std/utilities/format/format.functions/format.pass.cpp FAIL std/utilities/format/format.functions/locale-specific_form.pass.cpp FAIL -std/utilities/format/format.functions/vformat.locale.pass.cpp FAIL -std/utilities/format/format.functions/vformat.pass.cpp FAIL std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/ctad.static.compile.pass.cpp FAIL std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke.pass.cpp:0 FAIL std/utilities/function.objects/refwrap/refwrap.const/type_conv_ctor.pass.cpp:0 FAIL diff --git a/tests/std/lit.site.cfg.in b/tests/std/lit.site.cfg.in index 78cdb1a7130..9941c44e79c 100644 --- a/tests/std/lit.site.cfg.in +++ b/tests/std/lit.site.cfg.in @@ -19,12 +19,14 @@ config.test_format = stl.test.format.STLTestFormat() lit_config.expected_results = getattr(lit_config, 'expected_results', dict()) lit_config.include_dirs = getattr(lit_config, 'include_dirs', dict()) lit_config.library_dirs = getattr(lit_config, 'library_dirs', dict()) +lit_config.ruleset_dirs = getattr(lit_config, 'ruleset_dirs', dict()) lit_config.test_subdirs = getattr(lit_config, 'test_subdirs', dict()) lit_config.expected_results[config.name] = stl.test.file_parsing.parse_result_file('@STD_EXPECTED_RESULTS@') lit_config.include_dirs[config.name] = \ ['@STL_TESTED_HEADERS_DIR@', '@LIBCXX_SOURCE_DIR@/test/support', '@STL_SOURCE_DIR@/tests/std/include'] lit_config.library_dirs[config.name] = ['@STL_LIBRARY_OUTPUT_DIRECTORY@', '@TOOLSET_LIB@'] +lit_config.ruleset_dirs[config.name] = ['@STL_SOURCE_DIR@/tests/std/rulesets'] lit_config.test_subdirs[config.name] = ['@CMAKE_CURRENT_SOURCE_DIR@/tests'] lit_config.cxx_headers = '@STL_TESTED_HEADERS_DIR@' diff --git a/tests/std/rulesets/stl.ruleset b/tests/std/rulesets/stl.ruleset new file mode 100644 index 00000000000..7859a44da86 --- /dev/null +++ b/tests/std/rulesets/stl.ruleset @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/tests/std/test.lst b/tests/std/test.lst index 0c0c4e860f9..a116bca0b28 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -200,6 +200,8 @@ tests\GH_002030_asan_annotate_vector tests\GH_002039_byte_is_not_trivially_swappable tests\GH_002045_put_time_changes_errno tests\GH_002058_debug_iterator_race +# Needs special machinery to work in the MSVC-internal test harness, not yet implemented: +# tests\GH_002094_cpp_core_guidelines tests\GH_002120_streambuf_seekpos_and_seekoff tests\GH_002168_regex_overflow tests\GH_002206_unreserved_names @@ -218,6 +220,7 @@ tests\GH_002769_handle_deque_block_pointers tests\GH_002789_Hash_vec_Tidy tests\GH_002989_nothrow_unwrappable tests\GH_002992_unwrappable_iter_sent_pairs +tests\GH_003003_format_decimal_point tests\GH_003022_substr_allocator tests\GH_003105_piecewise_densities tests\GH_003119_error_category_ctor @@ -226,6 +229,8 @@ tests\GH_003570_allocate_at_least tests\GH_003617_vectorized_meow_element tests\GH_003676_format_large_hh_mm_ss_values tests\GH_003735_char_traits_signatures +tests\GH_003840_tellg_when_reading_lf_file_in_text_mode +tests\GH_003867_output_nan tests\LWG2381_num_get_floating_point tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function @@ -591,6 +596,7 @@ tests\P2322R6_ranges_alg_fold tests\P2374R4_checked_arithmetic_operations tests\P2374R4_views_cartesian_product tests\P2374R4_views_cartesian_product_death +tests\P2374R4_views_cartesian_product_recommended_practices tests\P2387R3_bind_back tests\P2387R3_pipe_support_for_user_defined_range_adaptors tests\P2401R0_conditional_noexcept_for_exchange @@ -618,6 +624,7 @@ tests\P2474R2_views_repeat_death tests\P2494R2_move_only_range_adaptors tests\P2505R5_monadic_functions_for_std_expected tests\P2517R1_apply_conditional_noexcept +tests\P2538R1_adl_proof_std_projected tests\P2609R3_relaxing_ranges_just_a_smidge tests\VSO_0000000_allocator_propagation tests\VSO_0000000_any_calling_conventions diff --git a/tests/std/tests/Dev09_056375_locale_cleanup/test.cpp b/tests/std/tests/Dev09_056375_locale_cleanup/test.cpp index 7a7cd8f9bf4..c37f325f7da 100644 --- a/tests/std/tests/Dev09_056375_locale_cleanup/test.cpp +++ b/tests/std/tests/Dev09_056375_locale_cleanup/test.cpp @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#define _SILENCE_CXX20_CODECVT_FACETS_DEPRECATION_WARNING + #include #include #include @@ -11,8 +13,35 @@ using namespace std; #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) -STATIC_ASSERT(noexcept(locale{} == locale{})); -STATIC_ASSERT(noexcept(locale{} != locale{})); +STATIC_ASSERT(noexcept(locale{} == locale{})); // strengthened +STATIC_ASSERT(noexcept(locale{} != locale{})); // strengthened + +STATIC_ASSERT(is_nothrow_default_constructible_v); // strengthened +STATIC_ASSERT(is_nothrow_default_constructible_v); // strengthened +STATIC_ASSERT(is_nothrow_default_constructible_v); // strengthened +STATIC_ASSERT(is_nothrow_default_constructible_v); // strengthened +STATIC_ASSERT(is_nothrow_default_constructible_v); // strengthened + +// Test that *_base classes are implicitly default constructible. + +template +void parameter_taker(const T&); // not defined + +template +constexpr bool is_implicitly_default_constructible = false; + +template +constexpr bool is_implicitly_default_constructible({}))>> = true; + +STATIC_ASSERT(is_implicitly_default_constructible); +STATIC_ASSERT(is_implicitly_default_constructible); +STATIC_ASSERT(is_implicitly_default_constructible); +STATIC_ASSERT(is_implicitly_default_constructible); +STATIC_ASSERT(is_implicitly_default_constructible); + +STATIC_ASSERT(!is_implicitly_default_constructible); +STATIC_ASSERT(!is_implicitly_default_constructible>); +STATIC_ASSERT(!is_implicitly_default_constructible>); void test_dll() { puts("Calling dll"); @@ -50,8 +79,131 @@ void test_exe_part2() { assert(!isspace(L'Z', locale())); } +#ifndef _M_CEE_PURE +locale make_unnamed_locale() { + locale result{locale{"C"}, &use_facet>(locale{"C"})}; + assert(result.name() == "*"); + return result; +} + +template +void test_locale_name_with_facet_pointer_one() { + { + locale result{locale{"C"}, static_cast(nullptr)}; + assert(result.name() == "C"); + } + { + locale result{make_unnamed_locale(), static_cast(nullptr)}; + assert(result.name() == "*"); + } + { + locale le{"C"}; + locale result{le, &use_facet(le)}; + assert(result.name() == "*"); + } + { + locale lunnamed{make_unnamed_locale()}; + locale result{lunnamed, &use_facet(lunnamed)}; + assert(result.name() == "*"); + } +} + +void test_locale_name_with_facet_pointer_all() { + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); +#ifdef __cpp_char8_t + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); +#endif // __cpp_char8_t + test_locale_name_with_facet_pointer_one>(); + + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); + + test_locale_name_with_facet_pointer_one>(); + test_locale_name_with_facet_pointer_one>(); +} + +void test_locale_name_with_another_locale_and_cats() { + locale lc{"C"}; + locale lunnamed{make_unnamed_locale()}; + { + locale result{lc, lc, locale::none}; + assert(result.name() != "*"); + } + { + locale result{lc, lunnamed, locale::none}; + assert(result.name() != "*"); + } + { + locale result{lunnamed, lc, locale::none}; + assert(result.name() == "*"); + } + { + locale result{lunnamed, lunnamed, locale::none}; + assert(result.name() == "*"); + } + + constexpr int cats_masks_count = 6; // collate | ctype | monetary | numeric | time | messages + for (int precats = 1; precats < (1 << cats_masks_count); ++precats) { + const locale::category cats = ((precats & (1 << 0)) != 0 ? locale::collate : locale::none) + | ((precats & (1 << 1)) != 0 ? locale::ctype : locale::none) + | ((precats & (1 << 2)) != 0 ? locale::monetary : locale::none) + | ((precats & (1 << 3)) != 0 ? locale::numeric : locale::none) + | ((precats & (1 << 4)) != 0 ? locale::time : locale::none) + | ((precats & (1 << 5)) != 0 ? locale::messages : locale::none); + { + locale result{lc, lc, cats}; + assert(result.name() != "*"); + } + { + locale result{lc, lunnamed, cats}; + assert(result.name() == "*"); + } + { + locale result{lunnamed, lc, cats}; + assert(result.name() == "*"); + } + { + locale result{lunnamed, lunnamed, cats}; + assert(result.name() == "*"); + } + } +} +#endif // _M_CEE_PURE + int main() { test_exe_part1(); test_dll(); test_exe_part2(); + +#ifndef _M_CEE_PURE + // test coverage for LWG-2295 + test_locale_name_with_facet_pointer_all(); + test_locale_name_with_another_locale_and_cats(); +#endif // _M_CEE_PURE } diff --git a/tests/std/tests/Dev10_500860_overloaded_address_of/test.cpp b/tests/std/tests/Dev10_500860_overloaded_address_of/test.cpp index 93b4ead540d..5718201bf03 100644 --- a/tests/std/tests/Dev10_500860_overloaded_address_of/test.cpp +++ b/tests/std/tests/Dev10_500860_overloaded_address_of/test.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING #define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS #include diff --git a/tests/std/tests/Dev10_709166_checked_and_unchecked_array_iterator/test.cpp b/tests/std/tests/Dev10_709166_checked_and_unchecked_array_iterator/test.cpp index 5addf960bdc..a1f8f5b611f 100644 --- a/tests/std/tests/Dev10_709166_checked_and_unchecked_array_iterator/test.cpp +++ b/tests/std/tests/Dev10_709166_checked_and_unchecked_array_iterator/test.cpp @@ -1,15 +1,74 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING + #include #include +#include #include +#include +#include #include #include #include +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +template +void check_checked_array_iterator_category_and_convertibility() { + STATIC_ASSERT(std::is_same_v::iterator_category, + std::random_access_iterator_tag>); + + STATIC_ASSERT(std::is_same_v::value_type, std::remove_cv_t>); + + STATIC_ASSERT(std::is_same_v::difference_type, std::ptrdiff_t>); + + STATIC_ASSERT(std::is_same_v::pointer, T*>); + + STATIC_ASSERT(std::is_same_v::reference, T&>); + + STATIC_ASSERT(std::is_convertible_v, stdext::checked_array_iterator>); + +#ifdef __cpp_lib_concepts + STATIC_ASSERT( + std::is_same_v::iterator_concept, std::contiguous_iterator_tag>); + + STATIC_ASSERT(std::contiguous_iterator>); +#endif // __cpp_lib_concepts +} + +template +void check_unchecked_array_iterator_category_and_convertibility() { + STATIC_ASSERT(std::is_same_v::iterator_category, + std::random_access_iterator_tag>); + + STATIC_ASSERT(std::is_same_v::value_type, std::remove_cv_t>); + + STATIC_ASSERT(std::is_same_v::difference_type, std::ptrdiff_t>); + + STATIC_ASSERT(std::is_same_v::pointer, T*>); + + STATIC_ASSERT(std::is_same_v::reference, T&>); + + STATIC_ASSERT( + std::is_convertible_v, stdext::unchecked_array_iterator>); + +#ifdef __cpp_lib_concepts + STATIC_ASSERT( + std::is_same_v::iterator_concept, std::contiguous_iterator_tag>); + + STATIC_ASSERT(std::contiguous_iterator>); +#endif // __cpp_lib_concepts +} + int main() { { + check_checked_array_iterator_category_and_convertibility(); + check_checked_array_iterator_category_and_convertibility(); + check_checked_array_iterator_category_and_convertibility>(); + + int* const p = new int[9]; for (int i = 0; i < 9; ++i) { @@ -19,31 +78,28 @@ int main() { auto cat = stdext::make_checked_array_iterator(p, 9); - static_assert(std::is_same_v>, - "stdext::make_checked_array_iterator(p, 9)'s return type is wrong!"); - - - auto dog = stdext::make_checked_array_iterator(p, 9, 3); - - static_assert(std::is_same_v>, - "stdext::make_checked_array_iterator(p, 9, 3)'s return type is wrong!"); - + STATIC_ASSERT(std::is_same_v>); - static_assert( - std::is_same_v::iterator_category, std::random_access_iterator_tag>, - "stdext::checked_array_iterator::iterator_category is wrong!"); +#if _HAS_CXX20 + assert(std::to_address(cat) == &*cat); + assert(std::to_address(cat + 8) == &*cat + 8); + assert(std::to_address(cat + 8) == std::to_address(cat) + 8); + assert(std::to_address(cat + 9) == std::to_address(cat) + 9); +#endif // _HAS_CXX20 - static_assert(std::is_same_v::value_type, int>, - "stdext::checked_array_iterator::value_type is wrong!"); - static_assert(std::is_same_v::difference_type, ptrdiff_t>, - "stdext::checked_array_iterator::difference_type is wrong!"); + auto dog = stdext::make_checked_array_iterator(p, 9, 3); - static_assert(std::is_same_v::pointer, int*>, - "stdext::checked_array_iterator::pointer is wrong!"); + STATIC_ASSERT(std::is_same_v>); - static_assert(std::is_same_v::reference, int&>, - "stdext::checked_array_iterator::reference is wrong!"); +#if _HAS_CXX20 + assert(std::to_address(dog) == &*dog); + assert(std::to_address(dog + 5) == &*dog + 5); + assert(std::to_address(dog + 5) == std::to_address(dog) + 5); + assert(std::to_address(dog - 3) == &*dog - 3); + assert(std::to_address(dog - 3) == std::to_address(dog) - 3); + assert(std::to_address(dog + 6) == std::to_address(dog) + 6); +#endif // _HAS_CXX20 { @@ -184,6 +240,11 @@ int main() { } { + check_unchecked_array_iterator_category_and_convertibility(); + check_unchecked_array_iterator_category_and_convertibility(); + check_unchecked_array_iterator_category_and_convertibility>(); + + int* const p = new int[9]; for (int i = 0; i < 9; ++i) { @@ -193,31 +254,28 @@ int main() { auto cat = stdext::make_unchecked_array_iterator(p); - static_assert(std::is_same_v>, - "stdext::make_unchecked_array_iterator(p)'s return type is wrong!"); + STATIC_ASSERT(std::is_same_v>); +#if _HAS_CXX20 + assert(std::to_address(cat) == &*cat); + assert(std::to_address(cat + 8) == &*cat + 8); + assert(std::to_address(cat + 8) == std::to_address(cat) + 8); + assert(std::to_address(cat + 9) == std::to_address(cat) + 9); +#endif // _HAS_CXX20 - auto dog = stdext::make_unchecked_array_iterator(p + 3); - - static_assert(std::is_same_v>, - "stdext::make_unchecked_array_iterator(p + 3)'s return type is wrong!"); + auto dog = stdext::make_unchecked_array_iterator(p + 3); - static_assert( - std::is_same_v::iterator_category, std::random_access_iterator_tag>, - "stdext::unchecked_array_iterator::iterator_category is wrong!"); - - static_assert(std::is_same_v::value_type, int>, - "stdext::unchecked_array_iterator::value_type is wrong!"); - - static_assert(std::is_same_v::difference_type, ptrdiff_t>, - "stdext::unchecked_array_iterator::difference_type is wrong!"); - - static_assert(std::is_same_v::pointer, int*>, - "stdext::unchecked_array_iterator::pointer is wrong!"); + STATIC_ASSERT(std::is_same_v>); - static_assert(std::is_same_v::reference, int&>, - "stdext::unchecked_array_iterator::reference is wrong!"); +#if _HAS_CXX20 + assert(std::to_address(dog) == &*dog); + assert(std::to_address(dog + 5) == &*dog + 5); + assert(std::to_address(dog + 5) == std::to_address(dog) + 5); + assert(std::to_address(dog - 3) == &*dog - 3); + assert(std::to_address(dog - 3) == std::to_address(dog) - 3); + assert(std::to_address(dog + 6) == std::to_address(dog) + 6); +#endif // _HAS_CXX20 { diff --git a/tests/std/tests/Dev10_709168_marking_iterators_as_checked/test.compile.pass.cpp b/tests/std/tests/Dev10_709168_marking_iterators_as_checked/test.compile.pass.cpp index 4e7f0833bce..754b6a632f2 100644 --- a/tests/std/tests/Dev10_709168_marking_iterators_as_checked/test.compile.pass.cpp +++ b/tests/std/tests/Dev10_709168_marking_iterators_as_checked/test.compile.pass.cpp @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING + #include #include #include diff --git a/tests/std/tests/Dev11_0000000_null_forward_iterators/test.cpp b/tests/std/tests/Dev11_0000000_null_forward_iterators/test.cpp index f9ea851fcc1..64e3e9d2cf4 100644 --- a/tests/std/tests/Dev11_0000000_null_forward_iterators/test.cpp +++ b/tests/std/tests/Dev11_0000000_null_forward_iterators/test.cpp @@ -3,6 +3,7 @@ #define _SILENCE_CXX23_ALIGNED_UNION_DEPRECATION_WARNING #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING +#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING #include #include diff --git a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp index a83150a9f36..51151f4a361 100644 --- a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp +++ b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp @@ -1615,6 +1615,11 @@ void test_function() { assert(f.target() == nullptr); assert(c.target() == nullptr); + assert(f.target() == nullptr); + assert(c.target() == nullptr); + assert(f.target() == nullptr); + assert(c.target() == nullptr); + f = triple; assert(f(1000) == 3000); assert(f.target_type() == typeid(int (*)(int))); @@ -1623,6 +1628,11 @@ void test_function() { assert(f.target() == nullptr); assert(c.target() == nullptr); + assert(f.target() == nullptr); + assert(c.target() == nullptr); + assert(f.target() == nullptr); + assert(c.target() == nullptr); + f = short_long; assert(f(1000) == 29); assert(f.target_type() == typeid(short (*)(long))); @@ -1630,6 +1640,11 @@ void test_function() { assert(c.target() == nullptr); assert(*f.target() == &short_long); assert(*c.target() == &short_long); + + assert(f.target() == nullptr); + assert(c.target() == nullptr); + assert(f.target() == nullptr); + assert(c.target() == nullptr); } diff --git a/tests/std/tests/Dev11_1074023_constexpr/test.cpp b/tests/std/tests/Dev11_1074023_constexpr/test.cpp index 58c32ebc3e2..d9b87f87247 100644 --- a/tests/std/tests/Dev11_1074023_constexpr/test.cpp +++ b/tests/std/tests/Dev11_1074023_constexpr/test.cpp @@ -625,6 +625,11 @@ STATIC_ASSERT(arr0.size() == 0); STATIC_ASSERT(arr0.max_size() != 5); STATIC_ASSERT(arr0.empty() == true); +// Also test DevCom-10299275, in which array was not a valid constant expression +// since we didn't initialize the single element. +constexpr array empty_array; +STATIC_ASSERT(empty_array.size() == 0); + constexpr istream_iterator istream_it{}; constexpr istreambuf_iterator istreambuf_it{}; diff --git a/tests/std/tests/Dev11_1150223_shared_mutex/test.cpp b/tests/std/tests/Dev11_1150223_shared_mutex/test.cpp index 44ca1f2b6f4..4a5ecdf2786 100644 --- a/tests/std/tests/Dev11_1150223_shared_mutex/test.cpp +++ b/tests/std/tests/Dev11_1150223_shared_mutex/test.cpp @@ -58,10 +58,7 @@ STATIC_ASSERT(noexcept(declval().native_handle())); #if _HAS_CXX20 STATIC_ASSERT(noexcept(declval().native_handle())); #endif // _HAS_CXX20 -STATIC_ASSERT(noexcept(declval().native_handle())); -STATIC_ASSERT(noexcept(declval().native_handle())); STATIC_ASSERT(noexcept(declval().native_handle())); -STATIC_ASSERT(noexcept(declval().native_handle())); // Also test mandatory and strengthened exception specification for try_lock(). STATIC_ASSERT(noexcept(declval().try_lock())); // strengthened diff --git a/tests/std/tests/GH_000431_copy_move_family/test.cpp b/tests/std/tests/GH_000431_copy_move_family/test.cpp index 9486d75d7f6..9b7cf5ab6e1 100644 --- a/tests/std/tests/GH_000431_copy_move_family/test.cpp +++ b/tests/std/tests/GH_000431_copy_move_family/test.cpp @@ -105,7 +105,9 @@ struct StatefulDerived2 : EmptyBase, StatefulBase {}; #ifdef __cpp_lib_is_pointer_interconvertible STATIC_ASSERT(is_pointer_interconvertible_base_of_v); STATIC_ASSERT(is_pointer_interconvertible_base_of_v); +#ifndef __EDG__ // TRANSITION, VSO-1849453 STATIC_ASSERT(!is_pointer_interconvertible_base_of_v); +#endif // ^^^ no workaround ^^^ STATIC_ASSERT(is_pointer_interconvertible_base_of_v); STATIC_ASSERT(is_pointer_interconvertible_base_of_v); #endif // __cpp_lib_is_pointer_interconvertible diff --git a/tests/std/tests/GH_000431_equal_family/test.cpp b/tests/std/tests/GH_000431_equal_family/test.cpp index 5461fbc81ad..9bd78f6bb3f 100644 --- a/tests/std/tests/GH_000431_equal_family/test.cpp +++ b/tests/std/tests/GH_000431_equal_family/test.cpp @@ -133,7 +133,9 @@ struct StatefulDerived2 : EmptyBase, StatefulBase {}; #ifdef __cpp_lib_is_pointer_interconvertible STATIC_ASSERT(is_pointer_interconvertible_base_of_v); STATIC_ASSERT(is_pointer_interconvertible_base_of_v); +#ifndef __EDG__ // TRANSITION, VSO-1849453 STATIC_ASSERT(!is_pointer_interconvertible_base_of_v); +#endif // ^^^ no workaround ^^^ STATIC_ASSERT(is_pointer_interconvertible_base_of_v); STATIC_ASSERT(is_pointer_interconvertible_base_of_v); #endif // __cpp_lib_is_pointer_interconvertible diff --git a/tests/std/tests/GH_000431_equal_memcmp_is_safe/test.compile.pass.cpp b/tests/std/tests/GH_000431_equal_memcmp_is_safe/test.compile.pass.cpp index 5159486e50b..560f081613f 100644 --- a/tests/std/tests/GH_000431_equal_memcmp_is_safe/test.compile.pass.cpp +++ b/tests/std/tests/GH_000431_equal_memcmp_is_safe/test.compile.pass.cpp @@ -141,9 +141,13 @@ struct StatefulPrivatelyDerived2 : private EmptyBase, private StatefulBase {}; STATIC_ASSERT(is_pointer_interconvertible_base_of_v); STATIC_ASSERT(is_pointer_interconvertible_base_of_v); STATIC_ASSERT(is_pointer_interconvertible_base_of_v); +#ifndef __EDG__ // TRANSITION, VSO-1849453 STATIC_ASSERT(!is_pointer_interconvertible_base_of_v); +#endif // ^^^ no workaround ^^^ STATIC_ASSERT(is_pointer_interconvertible_base_of_v); +#ifndef __EDG__ // TRANSITION, VSO-1849453 STATIC_ASSERT(!is_pointer_interconvertible_base_of_v); +#endif // ^^^ no workaround ^^^ STATIC_ASSERT(is_pointer_interconvertible_base_of_v); STATIC_ASSERT(is_pointer_interconvertible_base_of_v); STATIC_ASSERT(is_pointer_interconvertible_base_of_v); @@ -453,8 +457,10 @@ STATIC_ASSERT(test_equal_memcmp_is_safe_for_pointers()); STATIC_ASSERT(test_equal_memcmp_is_safe_for_pointers()); STATIC_ASSERT(test_equal_memcmp_is_safe_for_pointers()); +#ifndef __EDG__ // TRANSITION, VSO-1849453 STATIC_ASSERT(test_equal_memcmp_is_safe_for_pointers()); STATIC_ASSERT(test_equal_memcmp_is_safe_for_pointers()); +#endif // ^^^ no workaround ^^^ STATIC_ASSERT(test_equal_memcmp_is_safe_for_pointers()); STATIC_ASSERT(test_equal_memcmp_is_safe_for_pointers()); STATIC_ASSERT(test_equal_memcmp_is_safe_for_pointers()); diff --git a/tests/std/tests/GH_000431_iter_copy_move_cat/test.compile.pass.cpp b/tests/std/tests/GH_000431_iter_copy_move_cat/test.compile.pass.cpp index 682d00de985..e82adc5789f 100644 --- a/tests/std/tests/GH_000431_iter_copy_move_cat/test.compile.pass.cpp +++ b/tests/std/tests/GH_000431_iter_copy_move_cat/test.compile.pass.cpp @@ -309,9 +309,13 @@ struct StatefulPrivatelyDerived2 : private EmptyBase, private StatefulBase {}; STATIC_ASSERT(is_pointer_interconvertible_base_of_v); STATIC_ASSERT(is_pointer_interconvertible_base_of_v); STATIC_ASSERT(is_pointer_interconvertible_base_of_v); +#ifndef __EDG__ // TRANSITION, VSO-1849453 STATIC_ASSERT(!is_pointer_interconvertible_base_of_v); +#endif // ^^^ no workaround ^^^ STATIC_ASSERT(is_pointer_interconvertible_base_of_v); +#ifndef __EDG__ // TRANSITION, VSO-1849453 STATIC_ASSERT(!is_pointer_interconvertible_base_of_v); +#endif // ^^^ no workaround ^^^ STATIC_ASSERT(is_pointer_interconvertible_base_of_v); STATIC_ASSERT(is_pointer_interconvertible_base_of_v); STATIC_ASSERT(is_pointer_interconvertible_base_of_v); diff --git a/tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp b/tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp index 910117a97f3..f481702aa99 100644 --- a/tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp +++ b/tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp @@ -1,6 +1,17 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// some portions of this file are derived from libc++'s test files: +// * std/utilities/function.objects/func.bind_front/bind_front.pass.cpp + #include #include @@ -43,3 +54,230 @@ void test() { // COMPILE-ONLY STATIC_ASSERT(is_convertible_v>); } } + +// Also test expression-equivalence for the invocation on the return types of bind, bind_front, and bind_back + +#if _HAS_CXX17 +struct WeirdIdentity { + template + void operator()(T&&) = delete; + + template + constexpr T&& operator()(T&& t) const noexcept { + return static_cast(t); + } +}; + +static_assert( + is_invocable_v == is_invocable_v); +static_assert( + is_invocable_v == is_invocable_v); +static_assert(is_invocable_v + == is_invocable_v); +static_assert(is_invocable_v + == is_invocable_v); + +static_assert(is_invocable_r_v + == is_invocable_v(WeirdIdentity{}, placeholders::_1))&, int>); +static_assert(is_invocable_r_v + == is_invocable_v(WeirdIdentity{}, placeholders::_1)), int>); +static_assert(is_invocable_r_v + == is_invocable_v(WeirdIdentity{}, placeholders::_1))&, int>); +static_assert(is_invocable_r_v + == is_invocable_v(WeirdIdentity{}, placeholders::_1)), int>); + +static_assert(is_invocable_r_v + == is_invocable_v(WeirdIdentity{}, placeholders::_1))&, int>); +static_assert(is_invocable_r_v + == is_invocable_v(WeirdIdentity{}, placeholders::_1)), int>); +static_assert(is_invocable_r_v + == is_invocable_v(WeirdIdentity{}, placeholders::_1))&, int>); +static_assert(is_invocable_r_v + == is_invocable_v(WeirdIdentity{}, placeholders::_1)), int>); +#endif // _HAS_CXX17 + +#if _HAS_CXX20 +struct WeirdDual { + template + void operator()(T&&, U&&) & = delete; + + template + constexpr void operator()(T&&, U&&) const& noexcept {} + + template + constexpr void operator()(T&&, U&&) && noexcept {} + + template + constexpr void operator()(T&&, U&&) const&& = delete; +}; + +static_assert(is_invocable_v == is_invocable_v); +static_assert( + is_invocable_v == is_invocable_v); +static_assert(is_invocable_v == is_invocable_v); +static_assert( + is_invocable_v == is_invocable_v); + +// derived from libc++'s test file +void test_bind_front_deletion() { + // Make sure the bind_front unspecified-type is NOT invocable when the call would select a differently-qualified + // operator(). + // + // For example, if the call to `operator()() &` is ill-formed, the call to the unspecified-type + // should be ill-formed and not fall back to the `operator()() const&` overload. + { + // Make sure we delete the & overload when the underlying call isn't valid + struct F { + void operator()() & = delete; + void operator()() const& {} + void operator()() && {} + void operator()() const&& {} + }; + using X = decltype(bind_front(F{})); + static_assert(!is_invocable_v); + static_assert(is_invocable_v); + static_assert(is_invocable_v); + static_assert(is_invocable_v); + } + + // There's no way to make sure we delete the const& overload when the underlying call isn't valid, + // so we can't check this one. + + // Make sure we delete the && overload when the underlying call isn't valid + { + struct F { + void operator()() & {} + void operator()() const& {} + void operator()() && = delete; + void operator()() const&& {} + }; + using X = decltype(bind_front(F{})); + static_assert(is_invocable_v); + static_assert(is_invocable_v); + static_assert(!is_invocable_v); + static_assert(is_invocable_v); + } + + // Make sure we delete the const&& overload when the underlying call isn't valid + { + struct F { + void operator()() & {} + void operator()() const& {} + void operator()() && {} + void operator()() const&& = delete; + }; + using X = decltype(bind_front(F{})); + static_assert(is_invocable_v); + static_assert(is_invocable_v); + static_assert(is_invocable_v); + static_assert(!is_invocable_v); + } + + // Some examples by Tim Song + { + struct T {}; + struct F { + void operator()(T&&) const& {} + void operator()(T&&) && = delete; + }; + using X = decltype(bind_front(F{})); + static_assert(!is_invocable_v); + } + + { + struct T {}; + struct F { + void operator()(T const&) const {} + void operator()(T&&) const = delete; + }; + using X = decltype(bind_front(F{}, T{})); + static_assert(!is_invocable_v); + } +} +#endif // _HAS_CXX20 + +#if _HAS_CXX23 +static_assert(is_invocable_v == is_invocable_v); +static_assert( + is_invocable_v == is_invocable_v); +static_assert(is_invocable_v == is_invocable_v); +static_assert( + is_invocable_v == is_invocable_v); + +// derived from libc++'s test file +void test_bind_back_deletion() { + // Make sure the bind_back unspecified-type is NOT invocable when the call would select a differently-qualified + // operator(). + // + // For example, if the call to `operator()() &` is ill-formed, the call to the unspecified-type + // should be ill-formed and not fall back to the `operator()() const&` overload. + { + // Make sure we delete the & overload when the underlying call isn't valid + struct F { + void operator()() & = delete; + void operator()() const& {} + void operator()() && {} + void operator()() const&& {} + }; + using X = decltype(bind_back(F{})); + static_assert(!is_invocable_v); + static_assert(is_invocable_v); + static_assert(is_invocable_v); + static_assert(is_invocable_v); + } + + // There's no way to make sure we delete the const& overload when the underlying call isn't valid, + // so we can't check this one. + + // Make sure we delete the && overload when the underlying call isn't valid + { + struct F { + void operator()() & {} + void operator()() const& {} + void operator()() && = delete; + void operator()() const&& {} + }; + using X = decltype(bind_back(F{})); + static_assert(is_invocable_v); + static_assert(is_invocable_v); + static_assert(!is_invocable_v); + static_assert(is_invocable_v); + } + + // Make sure we delete the const&& overload when the underlying call isn't valid + { + struct F { + void operator()() & {} + void operator()() const& {} + void operator()() && {} + void operator()() const&& = delete; + }; + using X = decltype(bind_back(F{})); + static_assert(is_invocable_v); + static_assert(is_invocable_v); + static_assert(is_invocable_v); + static_assert(!is_invocable_v); + } + + // Some examples by Tim Song + { + struct T {}; + struct F { + void operator()(T&&) const& {} + void operator()(T&&) && = delete; + }; + using X = decltype(bind_back(F{})); + static_assert(!is_invocable_v); + } + + { + struct T {}; + struct F { + void operator()(T const&) const {} + void operator()(T&&) const = delete; + }; + using X = decltype(bind_back(F{}, T{})); + static_assert(!is_invocable_v); + } +} +#endif // _HAS_CXX23 diff --git a/tests/std/tests/GH_002094_cpp_core_guidelines/env.lst b/tests/std/tests/GH_002094_cpp_core_guidelines/env.lst new file mode 100644 index 00000000000..56a4f87e0b0 --- /dev/null +++ b/tests/std/tests/GH_002094_cpp_core_guidelines/env.lst @@ -0,0 +1,16 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\prefix.lst +RUNALL_CROSSLIST +PM_CL="/EHsc /w14640 /Zc:threadSafeInit-" +RUNALL_CROSSLIST +PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++14 /analyze:only /analyze:autolog- /analyze:plugin EspXEngine.dll /analyze:ruleset stl.ruleset" +PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++17 /permissive- /analyze:only /analyze:autolog- /analyze:plugin EspXEngine.dll /analyze:ruleset stl.ruleset" +PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++20 /permissive- /analyze:only /analyze:autolog- /analyze:plugin EspXEngine.dll /analyze:ruleset stl.ruleset" +PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /analyze:only /analyze:autolog- /analyze:plugin EspXEngine.dll /analyze:ruleset stl.ruleset" +PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive- /analyze:only /analyze:autolog- /analyze:plugin EspXEngine.dll /analyze:ruleset stl.ruleset" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /MD /std:c++14" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /MDd /std:c++17" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /MT /std:c++20 /permissive-" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /MTd /std:c++latest /permissive-" diff --git a/tests/std/tests/GH_002094_cpp_core_guidelines/test.compile.pass.cpp b/tests/std/tests/GH_002094_cpp_core_guidelines/test.compile.pass.cpp new file mode 100644 index 00000000000..1132aa12357 --- /dev/null +++ b/tests/std/tests/GH_002094_cpp_core_guidelines/test.compile.pass.cpp @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include <__msvc_all_public_headers.hpp> diff --git a/tests/std/tests/GH_003003_format_decimal_point/env.lst b/tests/std/tests/GH_003003_format_decimal_point/env.lst new file mode 100644 index 00000000000..d6d824b5879 --- /dev/null +++ b/tests/std/tests/GH_003003_format_decimal_point/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/GH_003003_format_decimal_point/test.cpp b/tests/std/tests/GH_003003_format_decimal_point/test.cpp new file mode 100644 index 00000000000..1b5d1e99f92 --- /dev/null +++ b/tests/std/tests/GH_003003_format_decimal_point/test.cpp @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +int main() { + assert(std::format("{:#.0}", 0.0) == "0."); + assert(std::format("{:#.1}", 0.0) == "0."); + assert(std::format("{:#.2}", 0.0) == "0."); + + assert(std::format("{:#.0}", 1200.0) == "1.e+03"); + assert(std::format("{:#.1}", 1200.0) == "1.e+03"); + assert(std::format("{:#.2}", 1200.0) == "1.2e+03"); + assert(std::format("{:#.3}", 1200.0) == "1.2e+03"); + assert(std::format("{:#.4}", 1200.0) == "1200."); + assert(std::format("{:#.5}", 1200.0) == "1200."); + assert(std::format("{:#.6}", 1200.0) == "1200."); + + assert(std::format("{:#.0}", 0.123) == "0.1"); + assert(std::format("{:#.1}", 0.123) == "0.1"); + assert(std::format("{:#.2}", 0.123) == "0.12"); + assert(std::format("{:#.3}", 0.123) == "0.123"); + assert(std::format("{:#.4}", 0.123) == "0.123"); + assert(std::format("{:#.5}", 0.123) == "0.123"); + + assert(std::format("{:#.0}", 10.1) == "1.e+01"); + assert(std::format("{:#.1}", 10.1) == "1.e+01"); + assert(std::format("{:#.2}", 10.1) == "10."); + assert(std::format("{:#.3}", 10.1) == "10.1"); + assert(std::format("{:#.4}", 10.1) == "10.1"); + assert(std::format("{:#.5}", 10.1) == "10.1"); +} diff --git a/tests/std/tests/GH_003570_allocate_at_least/test.cpp b/tests/std/tests/GH_003570_allocate_at_least/test.cpp index 65821ea0090..05a5f45cf52 100644 --- a/tests/std/tests/GH_003570_allocate_at_least/test.cpp +++ b/tests/std/tests/GH_003570_allocate_at_least/test.cpp @@ -4,8 +4,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -95,10 +97,36 @@ void test_syncstream() { test_stream_overflow(ss); } +template +constexpr bool always_false = false; + +template +struct icky_allocator : allocator { + template + struct rebind { + using other = icky_allocator; + }; + + allocation_result allocate_at_least(size_t) { + // The initial implementation of this feature had a problem with (icky) allocators that + // publicly derive from std::allocator and implement allocate/deallocate. The STL would + // call allocate_at_least in the std::allocator base (which would then call std::allocator::allocate), + // and would then call deallocate in the derived class (hiding the base implementation), a terrible mismatch. + // We now detect public derivation from std::allocator and avoid using allocate_at_least in that case. + static_assert(always_false); + } +}; + +void test_inheriting_allocator() { + vector> vec{2, 1, 4, 7, 5, 6, 3, 8}; + assert(accumulate(vec.begin(), vec.end(), 0, plus<>{}) == 36); +} + int main() { test_deque(); test_container, signalling_allocator>>(); test_container>>(); test_sstream(); test_syncstream(); + test_inheriting_allocator(); } diff --git a/tests/std/tests/GH_003840_tellg_when_reading_lf_file_in_text_mode/env.lst b/tests/std/tests/GH_003840_tellg_when_reading_lf_file_in_text_mode/env.lst new file mode 100644 index 00000000000..2de7aab2959 --- /dev/null +++ b/tests/std/tests/GH_003840_tellg_when_reading_lf_file_in_text_mode/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_17_matrix.lst diff --git a/tests/std/tests/GH_003840_tellg_when_reading_lf_file_in_text_mode/test.cpp b/tests/std/tests/GH_003840_tellg_when_reading_lf_file_in_text_mode/test.cpp new file mode 100644 index 00000000000..2482c9c6a1f --- /dev/null +++ b/tests/std/tests/GH_003840_tellg_when_reading_lf_file_in_text_mode/test.cpp @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include "temp_file_name.hpp" + +using namespace std; + +void test(const string& temp_file_name_str, const ios_base::openmode mode) { + filesystem::remove(temp_file_name_str); + + { + ofstream out{temp_file_name_str, mode}; + out << "Line A\n"; + out << "Line B\n"; + out << "Line C\n"; + } + + { + ifstream in{temp_file_name_str}; + string line; + + assert(getline(in, line)); + assert(line == "Line A"); + (void) in.tellg(); + + assert(getline(in, line)); + assert(line == "Line B"); + (void) in.tellg(); + + assert(getline(in, line)); + assert(line == "Line C"); + (void) in.tellg(); + + assert(!getline(in, line)); + } + + filesystem::remove(temp_file_name_str); +} + +int main() { + const string temp_file_name_str = temp_file_name(); + + test(temp_file_name_str, ios_base::out); + test(temp_file_name_str, ios_base::binary); +} diff --git a/tests/std/tests/GH_003867_output_nan/env.lst b/tests/std/tests/GH_003867_output_nan/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_003867_output_nan/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_003867_output_nan/test.cpp b/tests/std/tests/GH_003867_output_nan/test.cpp new file mode 100644 index 00000000000..a0c56d286a0 --- /dev/null +++ b/tests/std/tests/GH_003867_output_nan/test.cpp @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using namespace std; + +template +void test_gh_3867() { + // GH-3867 Writing NaN to the output stream with a set locale results in a weird output + ostringstream s; + s.imbue(locale("en-US")); + s << -numeric_limits::quiet_NaN(); + assert(s.str() == "-nan(ind)"); +} + +int main() { + test_gh_3867(); + test_gh_3867(); + test_gh_3867(); +} diff --git a/tests/std/tests/P0040R3_extending_memory_management_tools/test.cpp b/tests/std/tests/P0040R3_extending_memory_management_tools/test.cpp index 771425af7e0..dce64b84442 100644 --- a/tests/std/tests/P0040R3_extending_memory_management_tools/test.cpp +++ b/tests/std/tests/P0040R3_extending_memory_management_tools/test.cpp @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING + #include #include #include diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp index abeb44503aa..e040f958564 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -399,7 +399,6 @@ struct test_case_uninitialized_fill_n_parallel { }; int main() { -#ifndef _M_CEE // TRANSITION, VSO-1664463 parallel_test_case(test_case_uninitialized_default_construct_parallel{}, par); parallel_test_case(test_case_uninitialized_default_construct_n_parallel{}, par); parallel_test_case(test_case_uninitialized_default_construct_trivial_parallel{}, par); @@ -446,5 +445,4 @@ int main() { parallel_test_case(test_case_uninitialized_fill_parallel{}, unseq); parallel_test_case(test_case_uninitialized_fill_n_parallel{}, unseq); #endif // _HAS_CXX20 -#endif // _M_CEE } diff --git a/tests/std/tests/P0067R5_charconv/test.cpp b/tests/std/tests/P0067R5_charconv/test.cpp index b898d1902d4..c06b8444798 100644 --- a/tests/std/tests/P0067R5_charconv/test.cpp +++ b/tests/std/tests/P0067R5_charconv/test.cpp @@ -1170,9 +1170,6 @@ template pair std::__to_chars( wchar_t* const, wchar_t* const, const __floating_decimal_64, chars_format, const double); template pair std::__d2fixed_buffered_n(wchar_t*, wchar_t* const, const double, const uint32_t); -#if defined(__clang__) && defined(_M_IX86) // TRANSITION, LLVM-62762, fixed in Clang 16.0.3 -int main() {} -#else // ^^^ workaround / no workaround vvv int main(int argc, char** argv) { const auto start = chrono::steady_clock::now(); @@ -1201,4 +1198,3 @@ int main(int argc, char** argv) { puts("That was slow. Consider tuning PrefixesToTest and FractionBits to test fewer cases."); } } -#endif // ^^^ no workaround ^^^ diff --git a/tests/std/tests/P0218R1_filesystem/test.cpp b/tests/std/tests/P0218R1_filesystem/test.cpp index 1f53756d979..9dccd939413 100644 --- a/tests/std/tests/P0218R1_filesystem/test.cpp +++ b/tests/std/tests/P0218R1_filesystem/test.cpp @@ -2248,6 +2248,26 @@ void test_copy_symlink() { } } +void test_copy_directory_as_symlink() { + const path dirpath{L"./test-lwg2682-dir"sv}; + error_code ec; + create_directory(dirpath, ec); + EXPECT(good(ec)); + try { + copy(dirpath, L"./symlink"sv, copy_options::create_symlinks); + EXPECT(false); + } catch (filesystem_error& e) { + EXPECT(e.code().value() == static_cast(errc::is_a_directory)); + } + { + error_code copy_ec; + copy(dirpath, L"./symlink"sv, copy_options::create_symlinks, copy_ec); + EXPECT(copy_ec.value() == static_cast(errc::is_a_directory)); + } + remove_all(dirpath, ec); + EXPECT(good(ec)); +} + void equivalent_failure_test_case(const path& left, const path& right) { EXPECT(throws_filesystem_error([&] { EXPECT(!equivalent(left, right)); }, "equivalent", left, right)); @@ -3997,6 +4017,8 @@ int wmain(int argc, wchar_t* argv[]) { test_copy_symlink(); + test_copy_directory_as_symlink(); // per LWG-2682 + test_conversions(); test_file_size(); diff --git a/tests/std/tests/P0220R1_any/test.cpp b/tests/std/tests/P0220R1_any/test.cpp index cd69a914de5..6d3d25e3552 100644 --- a/tests/std/tests/P0220R1_any/test.cpp +++ b/tests/std/tests/P0220R1_any/test.cpp @@ -2604,6 +2604,11 @@ namespace msvc { } // namespace swap_ } // namespace modifiers +#ifdef _M_CEE // TRANSITION, VSO-1846195 +#pragma warning(push) +#pragma warning(disable : 5267) // definition of implicit copy constructor for 'X' is deprecated + // because it has a user-provided destructor +#endif // ^^^ workaround ^^^ namespace overaligned { template void test_one_alignment() { @@ -2612,6 +2617,12 @@ namespace msvc { struct aligned_type { alignas(align) unsigned char space[align]; +#ifndef _M_CEE // TRANSITION, VSO-1846195 + aligned_type() = default; + aligned_type(const aligned_type&) = default; + aligned_type& operator=(const aligned_type&) = default; +#endif // ^^^ no workaround ^^^ + ~aligned_type() noexcept { assert(reinterpret_cast(this) % align == 0); } @@ -2644,6 +2655,9 @@ namespace msvc { test_one_alignment<3>(); } } // namespace overaligned +#ifdef _M_CEE // TRANSITION, VSO-1846195 +#pragma warning(pop) +#endif // ^^^ workaround ^^^ namespace size_and_alignment { void run_test() { diff --git a/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp b/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp index 943f0220786..ac110e8d1ed 100644 --- a/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp +++ b/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp @@ -14,7 +14,6 @@ struct S { // Must be declared at namespace scope due to static data member }; constexpr bool test() { -#ifndef __EDG__ // TRANSITION, VSO-1268984 #ifndef __clang__ // TRANSITION, LLVM-48860 // is_layout_compatible tests { @@ -73,9 +72,11 @@ constexpr bool test() { ASSERT(is_layout_compatible_v); ASSERT(is_layout_compatible_v); +#ifndef __EDG__ // TRANSITION, VSO-1849458 ASSERT(is_layout_compatible_v); ASSERT(is_layout_compatible_v); ASSERT(is_layout_compatible_v); +#endif // ^^^ no workaround ^^^ ASSERT(!is_layout_compatible_v); ASSERT(!is_layout_compatible_v); @@ -246,7 +247,6 @@ constexpr bool test() { ASSERT(!is_pointer_interconvertible_with_class(static_cast(nullptr))); } #endif // __clang__ -#endif // __EDG__ return true; } diff --git a/tests/std/tests/P0645R10_text_formatting_args/test.cpp b/tests/std/tests/P0645R10_text_formatting_args/test.cpp index 98802790b38..24ceead553d 100644 --- a/tests/std/tests/P0645R10_text_formatting_args/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_args/test.cpp @@ -252,6 +252,18 @@ void test_lwg3810() { static_assert(same_as>); } +struct lvalue_only_visitor { + template + void operator()(T&&) const = delete; + template + void operator()(T&) const noexcept {} +}; + +template +void test_lvalue_only_visitation() { + visit_format_arg(lvalue_only_visitor{}, basic_format_arg{}); +} + int main() { test_basic_format_arg(); test_basic_format_arg(); @@ -259,6 +271,10 @@ int main() { test_format_arg_store(); test_visit_monostate(); test_visit_monostate(); + test_lwg3810(); test_lwg3810(); + + test_lvalue_only_visitation(); + test_lvalue_only_visitation(); } diff --git a/tests/std/tests/P0645R10_text_formatting_legacy_text_encoding/env.lst b/tests/std/tests/P0645R10_text_formatting_legacy_text_encoding/env.lst index fee12cbc26a..adb6a326162 100644 --- a/tests/std/tests/P0645R10_text_formatting_legacy_text_encoding/env.lst +++ b/tests/std/tests/P0645R10_text_formatting_legacy_text_encoding/env.lst @@ -21,9 +21,8 @@ PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /fp:stri PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive-" PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive" PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive- /analyze:only /analyze:autolog-" -# TRANSITION, VSO-1664463 -# PM_CL="/clr /MD /std:c++20" -# PM_CL="/clr /MDd /std:c++20" +PM_CL="/clr /MD /std:c++20" +PM_CL="/clr /MDd /std:c++20" # PM_CL="/std:c++20 /permissive- /BE /c /EHsc /MD" # PM_CL="/std:c++latest /permissive- /BE /c /EHsc /MTd" # PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /std:c++20 /permissive- /MD" diff --git a/tests/std/tests/P0718R2_atomic_smart_ptrs/test.cpp b/tests/std/tests/P0718R2_atomic_smart_ptrs/test.cpp index 710a09a4545..0150911878d 100644 --- a/tests/std/tests/P0718R2_atomic_smart_ptrs/test.cpp +++ b/tests/std/tests/P0718R2_atomic_smart_ptrs/test.cpp @@ -2,9 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include #include #include #include +#include #ifdef _DEBUG #include #endif // _DEBUG @@ -632,6 +634,13 @@ int main() { ensure_member_calls_compile>>(); ensure_member_calls_compile>>(); + // LWG-3893: LWG 3661 broke atomic> a; a = nullptr; + static_assert(is_nothrow_assignable_v>, nullptr_t>); + static_assert(is_nothrow_assignable_v>, nullptr_t>); + static_assert(is_nothrow_assignable_v>, nullptr_t>); + static_assert(is_nothrow_assignable_v>, nullptr_t>); + static_assert(is_nothrow_assignable_v>, nullptr_t>); + #ifdef _DEBUG sptr0 = {}; sptr1 = {}; diff --git a/tests/std/tests/P0896R4_views_lazy_split/test.cpp b/tests/std/tests/P0896R4_views_lazy_split/test.cpp index 55a785f3e23..9616e3eb214 100644 --- a/tests/std/tests/P0896R4_views_lazy_split/test.cpp +++ b/tests/std/tests/P0896R4_views_lazy_split/test.cpp @@ -337,7 +337,18 @@ constexpr bool instantiation_test() { return true; } +constexpr bool test_lwg_3904() { + auto r = views::single(0) | views::lazy_split(0); + auto i = r.begin(); + ++i; + decltype(as_const(r).begin()) j = i; + return j != r.end(); +} + int main() { STATIC_ASSERT(instantiation_test()); instantiation_test(); + + STATIC_ASSERT(test_lwg_3904()); + assert(test_lwg_3904()); } diff --git a/tests/std/tests/P1208R6_source_location/header.h b/tests/std/tests/P1208R6_source_location/header.h index 2bf8cdf2b31..e9c8b48bbb7 100644 --- a/tests/std/tests/P1208R6_source_location/header.h +++ b/tests/std/tests/P1208R6_source_location/header.h @@ -12,9 +12,11 @@ constexpr void header_test() { assert(x.line() == __LINE__ - 1); #ifdef __clang__ assert(x.column() == 20); -#else // ^^^ defined(__clang__) / !defined(__clang__) vvv +#elif defined(__EDG__) + assert(x.column() == 45); +#else // ^^^ EDG / C1XX vvv assert(x.column() == 37); -#endif // ^^^ !defined(__clang__) ^^^ +#endif // ^^^ C1XX ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(x.function_name() == "header_test"sv); #else // ^^^ workaround / no workaround vvv diff --git a/tests/std/tests/P1208R6_source_location/test.cpp b/tests/std/tests/P1208R6_source_location/test.cpp index d41dc8d3194..4640ca5c131 100644 --- a/tests/std/tests/P1208R6_source_location/test.cpp +++ b/tests/std/tests/P1208R6_source_location/test.cpp @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef __EDG__ // TRANSITION, VSO-1285779 #include "header.h" #include #include @@ -21,9 +20,11 @@ constexpr auto g = source_location::current(); static_assert(g.line() == __LINE__ - 1); #ifdef __clang__ static_assert(g.column() == 20); -#else // ^^^ defined(__clang__) / !defined(__clang__) vvv +#elif defined(__EDG__) +static_assert(g.column() == 45); +#else // ^^^ EDG / C1XX vvv static_assert(g.column() == 37); -#endif // ^^^ !defined(__clang__) ^^^ +#endif // ^^^ C1XX ^^^ static_assert(g.function_name() == ""sv); static_assert(string_view{g.file_name()}.ends_with(test_cpp)); @@ -55,9 +56,11 @@ constexpr void local_test() { assert(x.line() == __LINE__ - 1); #ifdef __clang__ assert(x.column() == 20); -#else // ^^^ defined(__clang__) / !defined(__clang__) vvv +#elif defined(__EDG__) + assert(x.column() == 45); +#else // ^^^ EDG / C1XX vvv assert(x.column() == 37); -#endif // ^^^ !defined(__clang__) ^^^ +#endif // ^^^ C1XX ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(x.function_name() == "local_test"sv); #else // ^^^ workaround / no workaround vvv @@ -81,7 +84,11 @@ constexpr void argument_test( constexpr void sloc_constructor_test() { const s x; assert(x.loc.line() == __LINE__ - 1); +#ifdef __EDG__ + assert(x.loc.column() == 14); +#else // ^^^ defined(__EDG__) / !defined(__EDG__) vvv assert(x.loc.column() == 13); +#endif // ^^^ !defined(__EDG__) ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(x.loc.function_name() == "sloc_constructor_test"sv); #else // ^^^ workaround / no workaround vvv @@ -99,9 +106,11 @@ constexpr void different_constructor_test() { assert(x.loc.line() == s_int_line); #ifdef __clang__ assert(x.loc.column() == 15); -#else // ^^^ defined(__clang__) / !defined(__clang__) vvv +#elif defined(__EDG__) + assert(x.loc.column() == 22); +#else // ^^^ EDG / C1XX vvv assert(x.loc.column() == 5); -#endif // ^^^ !defined(__clang__) ^^^ +#endif // ^^^ C1XX ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(x.loc.function_name() == "s"sv); #elif defined(_M_IX86) // ^^^ workaround / no workaround vvv @@ -115,7 +124,11 @@ constexpr void different_constructor_test() { constexpr void sub_member_test() { const s2 s; assert(s.x.loc.line() == __LINE__ - 1); +#ifdef __EDG__ + assert(s.x.loc.column() == 15); +#else // ^^^ defined(__EDG__) / !defined(__EDG__) vvv assert(s.x.loc.column() == 14); +#endif // ^^^ !defined(__EDG__) ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(s.x.loc.function_name() == "sub_member_test"sv); #else // ^^^ workaround / no workaround vvv @@ -131,9 +144,11 @@ constexpr void sub_member_test() { assert(s_i.x.loc.line() == s2_int_line); #ifdef __clang__ assert(s_i.x.loc.column() == 15); -#else // ^^^ defined(__clang__) / !defined(__clang__) vvv +#elif defined(__EDG__) + assert(s_i.x.loc.column() == 23); +#else // ^^^ EDG / C1XX vvv assert(s_i.x.loc.column() == 5); -#endif // ^^^ !defined(__clang__) ^^^ +#endif // ^^^ C1XX ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(s_i.x.loc.function_name() == "s2"sv); #elif defined(_M_IX86) // ^^^ workaround / no workaround vvv @@ -154,10 +169,13 @@ constexpr void lambda_test() { #ifdef __clang__ assert(x1.column() == 28); assert(x2.column() == 33); -#else // ^^^ defined(__clang__) / !defined(__clang__) vvv +#elif defined(__EDG__) + assert(x1.column() == 53); + assert(x2.column() == 58); +#else // ^^^ EDG / C1XX vvv assert(x1.column() == 52); assert(x2.column() == 50); -#endif // ^^^ !defined(__clang__) ^^^ +#endif // ^^^ C1XX ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(x1.function_name() == "lambda_test"sv); assert(x2.function_name() == "operator()"sv); @@ -185,9 +203,11 @@ constexpr void function_template_test() { assert(x1.line() == __LINE__ - 5); #ifdef __clang__ assert(x1.column() == 12); -#else // ^^^ defined(__clang__) / !defined(__clang__) vvv +#elif defined(__EDG__) + assert(x1.column() == 37); +#else // ^^^ EDG / C1XX vvv assert(x1.column() == 29); -#endif // ^^^ !defined(__clang__) ^^^ +#endif // ^^^ C1XX ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(x1.function_name() == "function_template"sv); #else // ^^^ workaround / no workaround vvv @@ -209,14 +229,21 @@ constexpr void function_template_test() { constexpr bool test() { copy_test(); local_test(); +#ifdef __EDG__ + argument_test(__LINE__, 31); +#else // ^^^ defined(__EDG__) / !defined(__EDG__) vvv argument_test(__LINE__, 5); +#endif // ^^^ !defined(__EDG__) ^^^ #ifdef __clang__ const auto loc = source_location::current(); argument_test(__LINE__ - 1, 22, loc); -#else // ^^^ defined(__clang__) / !defined(__clang__) vvv +#elif defined(__EDG__) + const auto loc = source_location::current(); + argument_test(__LINE__ - 1, 47, loc); +#else // ^^^ EDG / C1XX vvv const auto loc = source_location::current(); argument_test(__LINE__ - 1, 39, loc); -#endif // ^^^ !defined(__clang__) ^^^ +#endif // ^^^ C1XX ^^^ sloc_constructor_test(); different_constructor_test(); sub_member_test(); @@ -226,17 +253,16 @@ constexpr bool test() { return true; } +#ifndef __EDG__ // TRANSITION, VSO-1849463 // Also test GH-2822 Failed to specialize std::invoke on operator() with default argument // std::source_location::current() void test_gh_2822() { // COMPILE-ONLY invoke([](source_location = source_location::current()) {}); } +#endif // ^^^ no workaround ^^^ int main() { test(); static_assert(test()); return 0; } -#else // ^^^ !defined(__EDG__) / defined(__EDG__) vvv -int main() {} -#endif // ^^^ defined(__EDG__) ^^^ diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp index aee2e256ee3..45b77573ce6 100644 --- a/tests/std/tests/P1614R2_spaceship/test.cpp +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING + #include #include #include diff --git a/tests/std/tests/P2374R4_views_cartesian_product/test.cpp b/tests/std/tests/P2374R4_views_cartesian_product/test.cpp index eedcde49eea..b38606f23db 100644 --- a/tests/std/tests/P2374R4_views_cartesian_product/test.cpp +++ b/tests/std/tests/P2374R4_views_cartesian_product/test.cpp @@ -922,57 +922,6 @@ using move_only_view = test::range}, test::ProxyRef{!derived_from}, test::CanView::yes, test::Copyability::move_only>; -namespace check_recommended_practice_implementation { // MSVC STL specific behavior - using ranges::cartesian_product_view, ranges::empty_view, ranges::single_view, views::all_t, ranges::range_size_t, - ranges::range_difference_t, ranges::ref_view, ranges::owning_view; - using Arr = array; - using Vec = vector; - using Span = span; - - // Computing product for such small array does not require big range_size_t - STATIC_ASSERT(sizeof(range_size_t>>) <= sizeof(size_t)); - STATIC_ASSERT(sizeof(range_size_t, all_t>>) <= sizeof(size_t)); - STATIC_ASSERT(sizeof(range_size_t, all_t, all_t>>) <= sizeof(size_t)); - - // Same thing with range_difference_t - STATIC_ASSERT(sizeof(range_difference_t>>) <= sizeof(ptrdiff_t)); - STATIC_ASSERT(sizeof(range_difference_t, all_t>>) <= sizeof(ptrdiff_t)); - STATIC_ASSERT( - sizeof(range_difference_t, all_t, all_t>>) <= sizeof(ptrdiff_t)); - - // Computing product for such small span does not require big range_size_t - STATIC_ASSERT(sizeof(range_size_t>>) <= sizeof(size_t)); - STATIC_ASSERT(sizeof(range_size_t, all_t>>) <= sizeof(size_t)); - STATIC_ASSERT( - sizeof(range_size_t, all_t, all_t>>) <= sizeof(size_t)); - - // Same thing with range_difference_t - STATIC_ASSERT(sizeof(range_difference_t>>) <= sizeof(ptrdiff_t)); - STATIC_ASSERT(sizeof(range_difference_t, all_t>>) <= sizeof(ptrdiff_t)); - STATIC_ASSERT( - sizeof(range_difference_t, all_t, all_t>>) <= sizeof(ptrdiff_t)); - - // Check 'single_view' and 'empty_view' - STATIC_ASSERT(sizeof(range_size_t, single_view>>) <= sizeof(size_t)); - STATIC_ASSERT( - sizeof(range_difference_t, single_view>>) <= sizeof(ptrdiff_t)); - - // Check 'ref_view<(const) V>' and 'owning_view' - STATIC_ASSERT(sizeof(range_size_t, ref_view, owning_view>>) - <= sizeof(size_t)); - STATIC_ASSERT( - sizeof(range_difference_t, ref_view, owning_view>>) - <= sizeof(ptrdiff_t)); - - // One vector should not use big integer-class type... - STATIC_ASSERT(sizeof(range_size_t>>) <= sizeof(size_t)); - STATIC_ASSERT(sizeof(range_difference_t>>) <= sizeof(ptrdiff_t)); - - // ... but two vectors will - STATIC_ASSERT(sizeof(range_size_t, all_t>>) > sizeof(size_t)); - STATIC_ASSERT(sizeof(range_difference_t, all_t>>) > sizeof(ptrdiff_t)); -} // namespace check_recommended_practice_implementation - // GH-3733: cartesian_product_view would incorrectly reject a call to size() claiming that big*big*big*0 is not // representable as range_size_t because big*big*big is not. constexpr void test_gh_3733() { diff --git a/tests/std/tests/P2374R4_views_cartesian_product_recommended_practices/env.lst b/tests/std/tests/P2374R4_views_cartesian_product_recommended_practices/env.lst new file mode 100644 index 00000000000..8ac7033b206 --- /dev/null +++ b/tests/std/tests/P2374R4_views_cartesian_product_recommended_practices/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst diff --git a/tests/std/tests/P2374R4_views_cartesian_product_recommended_practices/test.compile.pass.cpp b/tests/std/tests/P2374R4_views_cartesian_product_recommended_practices/test.compile.pass.cpp new file mode 100644 index 00000000000..42f982da641 --- /dev/null +++ b/tests/std/tests/P2374R4_views_cartesian_product_recommended_practices/test.compile.pass.cpp @@ -0,0 +1,497 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Check MSVC-STL internal machinery + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using ranges::_Compile_time_max_size, ranges::cartesian_product_view, ranges::sized_range, ranges::range_difference_t, + ranges::range_size_t, views::all_t; + +template +using cpv_size_t = range_size_t>; + +template +using cpv_difference_t = range_difference_t>; + +template +using cpv_const_size_t = range_size_t>; + +template +using cpv_const_difference_t = range_difference_t>; + +#ifdef _WIN64 +constexpr bool is_64_bit = true; +#else // ^^^ 64 bit ^^^ / vvv 32 bit vvv +constexpr bool is_64_bit = false; +#endif // ^^^ 32 bit ^^^ + +constexpr void check_array() { + // Check '_Compile_time_max_size' type trait + static_assert(_Compile_time_max_size == 3); + static_assert(_Compile_time_max_size == 9); + + // Check '_Compile_time_max_size' type trait for const arrays + static_assert(_Compile_time_max_size == 3); + static_assert(_Compile_time_max_size == 9); + + // Computing cartesian product for small arrays does not require big range_size_t + using A1 = all_t; + static_assert(sizeof(cpv_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_size_t) <= sizeof(size_t)); + + // Same thing with range_difference_t + static_assert(sizeof(cpv_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_difference_t) <= sizeof(ptrdiff_t)); + +#ifndef __clang__ // TRANSITION, Clang 17 + // Computing cartesian product for big arrays requires bigger types + using A2 = all_t; + static_assert(sizeof(cpv_size_t) > sizeof(size_t)); + static_assert(sizeof(cpv_difference_t) > sizeof(ptrdiff_t)); +#endif // __clang__ +} + +constexpr void check_std_array() { + // Check '_Compile_time_max_size' type trait + static_assert(_Compile_time_max_size> == 0); + static_assert(_Compile_time_max_size> == 3); + static_assert(_Compile_time_max_size> == 9); + + // Check '_Compile_time_max_size' type trait for const arrays + static_assert(_Compile_time_max_size> == 0); + static_assert(_Compile_time_max_size> == 3); + static_assert(_Compile_time_max_size> == 9); + + // Computing cartesian product for small arrays does not require big range_size_t + using A1 = all_t>; + static_assert(sizeof(cpv_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_const_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_const_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_const_size_t) <= sizeof(size_t)); + + // Same thing with range_difference_t + static_assert(sizeof(cpv_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_const_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_const_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_const_difference_t) <= sizeof(ptrdiff_t)); + + // Computing cartesian product for big arrays requires bigger types + using A2 = all_t&>; + static_assert(sizeof(cpv_size_t) > sizeof(size_t)); + static_assert(sizeof(cpv_difference_t) > sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_const_size_t) > sizeof(size_t)); + static_assert(sizeof(cpv_const_difference_t) > sizeof(ptrdiff_t)); +} + +constexpr void check_span() { + // Check '_Compile_time_max_size' type trait + static_assert(_Compile_time_max_size> == 0); + static_assert(_Compile_time_max_size> == 3); + static_assert(_Compile_time_max_size> == 9); + static_assert(_Compile_time_max_size> == (numeric_limits::size_type>::max)()); + + // Check '_Compile_time_max_size' type trait for const spans + static_assert(_Compile_time_max_size> == 0); + static_assert(_Compile_time_max_size> == 3); + static_assert(_Compile_time_max_size> == 9); + static_assert(_Compile_time_max_size> == (numeric_limits::size_type>::max)()); + + // Computing cartesian product for small spans does not require big range_size_t + using S1 = all_t>; + static_assert(sizeof(cpv_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_const_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_const_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_const_size_t) <= sizeof(size_t)); + + // Same thing with range_difference_t + static_assert(sizeof(cpv_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_const_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_const_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_const_difference_t) <= sizeof(ptrdiff_t)); + + // Computing cartesian product for big spans requires bigger types + using S2 = span; + static_assert(sizeof(cpv_size_t) > sizeof(size_t)); + static_assert(sizeof(cpv_difference_t) > sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_const_size_t) > sizeof(size_t)); + static_assert(sizeof(cpv_const_difference_t) > sizeof(ptrdiff_t)); +} + +constexpr void check_empty_view() { + using ranges::empty_view; + + // Check '_Compile_time_max_size' type trait + static_assert(_Compile_time_max_size> == 0); + static_assert(_Compile_time_max_size> == 0); + static_assert(_Compile_time_max_size> == 0); + static_assert(_Compile_time_max_size> == 0); + + using E = empty_view; + static_assert(sizeof(cpv_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_const_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_const_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_const_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_const_difference_t) <= sizeof(ptrdiff_t)); +} + +constexpr void check_single_view() { + using ranges::single_view; + + // Check '_Compile_time_max_size' type trait + static_assert(_Compile_time_max_size> == 1); + static_assert(_Compile_time_max_size> == 1); + static_assert(_Compile_time_max_size> == 1); + static_assert(_Compile_time_max_size> == 1); + + using S = single_view; + static_assert(sizeof(cpv_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_const_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_const_difference_t) <= sizeof(ptrdiff_t)); + static_assert(sizeof(cpv_const_size_t) <= sizeof(size_t)); + static_assert(sizeof(cpv_const_difference_t) <= sizeof(ptrdiff_t)); +} + +enum class CheckConstAdaptor : bool { no, yes }; + +template