From 62205ab155d093e71dd9588a78f02c5396c3c14b Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Mon, 19 Aug 2024 05:22:26 -0700 Subject: [PATCH 01/42] Workaround Intellisense bug in some `ranges::to` tests (#4895) --- tests/std/tests/P1206R7_ranges_to_mappish/test.cpp | 2 ++ tests/std/tests/P1206R7_ranges_to_misc/test.cpp | 8 ++++++++ tests/std/tests/P1206R7_ranges_to_sequence/test.cpp | 2 ++ tests/std/tests/P1206R7_ranges_to_settish/test.cpp | 2 ++ 4 files changed, 14 insertions(+) diff --git a/tests/std/tests/P1206R7_ranges_to_mappish/test.cpp b/tests/std/tests/P1206R7_ranges_to_mappish/test.cpp index 6ba6e3fa3bb..5eea58bcc46 100644 --- a/tests/std/tests/P1206R7_ranges_to_mappish/test.cpp +++ b/tests/std/tests/P1206R7_ranges_to_mappish/test.cpp @@ -156,11 +156,13 @@ struct mappish_instantiator { assert(c5.get_allocator().state == 13); assert(ranges::is_permutation(c5, expected, any_pair_eq)); } +#ifndef __EDG__ // TRANSITION, VSO-2208356 { std::same_as auto c6 = R{some_pairs} | ranges::to(Alloc{13}); assert(c6.get_allocator().state == 13); assert(ranges::is_permutation(c6, expected, any_pair_eq)); } +#endif // ^^^ no workaround ^^^ { std::same_as auto c7 = R{some_pairs} | ranges::to(Alloc{13}); assert(c7.get_allocator().state == 13); diff --git a/tests/std/tests/P1206R7_ranges_to_misc/test.cpp b/tests/std/tests/P1206R7_ranges_to_misc/test.cpp index 0e433f419a4..5e5757bbae7 100644 --- a/tests/std/tests/P1206R7_ranges_to_misc/test.cpp +++ b/tests/std/tests/P1206R7_ranges_to_misc/test.cpp @@ -54,6 +54,7 @@ struct reservable { }; constexpr bool test_reservable() { +#ifndef __EDG__ // TRANSITION, VSO-2208356 int some_ints[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; { std::same_as auto r = some_ints | ranges::to(secret_key); @@ -61,6 +62,7 @@ constexpr bool test_reservable() { assert(r.cap_ == ranges::size(some_ints)); assert(r.reserved_ == ranges::size(some_ints)); } +#endif // ^^^ no workaround ^^^ return true; } @@ -91,12 +93,14 @@ constexpr bool test_common_constructible() { assert(c0.last_ == ranges::end(some_ints)); assert(c0.args_ == 3); } +#ifndef __EDG__ // TRANSITION, VSO-2208356 { std::same_as auto c1 = some_ints | ranges::to(secret_key); assert(c1.first_ == ranges::begin(some_ints)); assert(c1.last_ == ranges::end(some_ints)); assert(c1.args_ == 3); } +#endif // ^^^ no workaround ^^^ // Verify that more than one argument can be passed after the range: { @@ -105,12 +109,14 @@ constexpr bool test_common_constructible() { assert(c2.last_ == ranges::end(some_ints)); assert(c2.args_ == 4); } +#ifndef __EDG__ // TRANSITION, VSO-2208356 { std::same_as auto c3 = some_ints | ranges::to(secret_key, 3.14); assert(c3.first_ == ranges::begin(some_ints)); assert(c3.last_ == ranges::end(some_ints)); assert(c3.args_ == 4); } +#endif // ^^^ no workaround ^^^ return true; } @@ -296,6 +302,7 @@ constexpr void test_lwg4016_per_kind() { std::same_as auto vec = std::views::iota(0, 42) | ranges::to(); assert(ranges::equal(vec, std::views::iota(0, 42))); } +#ifndef __EDG__ // TRANSITION, VSO-2208356 { std::same_as auto vec = std::views::iota(0, 42) | ranges::to(std::allocator{}); assert(ranges::equal(vec, std::views::iota(0, 42))); @@ -308,6 +315,7 @@ constexpr void test_lwg4016_per_kind() { std::same_as auto vec = std::views::empty | ranges::to(std::size_t{42}, std::allocator{}); assert(ranges::equal(vec, std::views::repeat(0, 42))); } +#endif // ^^^ no workaround ^^^ { std::same_as auto vec = ranges::to(std::views::iota(0, 42), std::initializer_list{-3, -2, -1}); assert(ranges::equal(vec, std::views::iota(-3, 42))); diff --git a/tests/std/tests/P1206R7_ranges_to_sequence/test.cpp b/tests/std/tests/P1206R7_ranges_to_sequence/test.cpp index 9ee7894d9f7..85118788f2d 100644 --- a/tests/std/tests/P1206R7_ranges_to_sequence/test.cpp +++ b/tests/std/tests/P1206R7_ranges_to_sequence/test.cpp @@ -145,11 +145,13 @@ struct sequence_instantiator { assert(c5.get_allocator().state == 13); assert(ranges::equal(c5, meow)); } +#ifndef __EDG__ // TRANSITION, VSO-2208356 { std::same_as auto c6 = R{meow} | ranges::to(Alloc{13}); assert(c6.get_allocator().state == 13); assert(ranges::equal(c6, meow)); } +#endif // ^^^ no workaround ^^^ { std::same_as auto c7 = R{meow} | ranges::to(Alloc{13}); assert(c7.get_allocator().state == 13); diff --git a/tests/std/tests/P1206R7_ranges_to_settish/test.cpp b/tests/std/tests/P1206R7_ranges_to_settish/test.cpp index df56e6fccc5..8436f75f3ea 100644 --- a/tests/std/tests/P1206R7_ranges_to_settish/test.cpp +++ b/tests/std/tests/P1206R7_ranges_to_settish/test.cpp @@ -150,11 +150,13 @@ struct settish_instantiator { assert(c5.get_allocator().state == 13); assert(ranges::is_permutation(c5, expected)); } +#ifndef __EDG__ // TRANSITION, VSO-2208356 { std::same_as auto c6 = R{some_ints} | ranges::to(Alloc{13}); assert(c6.get_allocator().state == 13); assert(ranges::is_permutation(c6, expected)); } +#endif // ^^^ no workaround ^^^ { std::same_as auto c7 = R{some_ints} | ranges::to(Alloc{13}); assert(c7.get_allocator().state == 13); From 1a84ba008752478ff15db16a39a1179d021b3427 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 25 Aug 2024 10:27:54 -0700 Subject: [PATCH 02/42] Update llvm-project (#4910) --- llvm-project | 2 +- stl/inc/ostream | 2 +- tests/libcxx/expected_results.txt | 43 ++++++++++++++----------------- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/llvm-project b/llvm-project index 1b7631a699e..886b76128fb 160000 --- a/llvm-project +++ b/llvm-project @@ -1 +1 @@ -Subproject commit 1b7631a699e6af7f497548a1ceb5be0570c60ed0 +Subproject commit 886b76128fba5f995c8c8e24aaa2030b59dec01a diff --git a/stl/inc/ostream b/stl/inc/ostream index b682a8b68bd..2b64fe185cc 100644 --- a/stl/inc/ostream +++ b/stl/inc/ostream @@ -100,7 +100,7 @@ public: } const auto _Tied = _Ostr.tie(); - if (!_Tied || _Tied == &_Ostr) { + if (!_Tied || _Tied == _STD addressof(_Ostr)) { _Ok = true; return; } diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index d1c69193af2..6f0059892bd 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -34,21 +34,16 @@ std/utilities/format/format.range/format.range.formatter/format.functions.vforma std/utilities/format/format.range/format.range.fmtset/format.functions.format.pass.cpp FAIL std/utilities/format/format.range/format.range.fmtset/format.functions.vformat.pass.cpp FAIL -# LLVM-100498: [libc++][test] alg.find.last tests assume that std::array iterators are pointers -std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp FAIL -std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if.pass.cpp FAIL -std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if_not.pass.cpp FAIL - -# LLVM-100502: [libc++][test] Bogus loops in time.cal.ymdlast.nonmembers/comparisons.pass.cpp -# Note: The :1 (ASAN) configuration doesn't run static analysis. -std/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.nonmembers/comparisons.pass.cpp:0 FAIL - -# LLVM-100504: [libc++][test] Fix Clang -Wunused-variable warnings in time.zone.members/to_sys.pass.cpp -std/time/time.zone/time.zone.timezone/time.zone.members/to_sys.pass.cpp:2 FAIL - # LLVM-100506: [libc++][test] Precondition violation in rand.dist.uni.real/param_ctor.pass.cpp std/numerics/rand/rand.dist/rand.dist.uni/rand.dist.uni.real/param_ctor.pass.cpp FAIL +# LLVM-105878: [libc++][test] fp_compare.h includes non-portable <__config> +std/numerics/c.math/cmath.pass.cpp FAIL +std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.float.pass.cpp FAIL + +# LLVM-105966: [libc++][test] Fix is_always_lock_free test +std/atomics/atomics.lockfree/is_always_lock_free.cpp FAIL + # Non-Standard regex behavior. # "It seems likely that the test is still non-conforming due to how libc++ handles the 'w' character class." std/re/re.traits/lookup_classname.pass.cpp FAIL @@ -85,9 +80,6 @@ std/numerics/rand/rand.util/rand.util.canonical/generate_canonical.pass.cpp FAIL # Test expects __cpp_lib_chrono to have the old value 201611L for P0505R0; we define the C++20 value 201907L for P1466R3. std/language.support/support.limits/support.limits.general/chrono.version.compile.pass.cpp FAIL -# Test expects __cpp_lib_three_way_comparison to have the old value 201711L for P0768R1; we define the C++20 value 201907L for P1614R2. -std/language.support/support.limits/support.limits.general/compare.version.compile.pass.cpp FAIL - # Tests expect __cpp_lib_ranges to have the old value 201811L for P0896R4; we define the C++20 value 201911L for P1716R3. std/language.support/support.limits/support.limits.general/algorithm.version.compile.pass.cpp FAIL std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp FAIL @@ -244,6 +236,9 @@ std/language.support/support.limits/support.limits.general/cstdlib.version.compi # P2255R2 "Type Traits To Detect References Binding To Temporaries" std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp FAIL +# P3107R5 "Permit An Efficient Implementation Of " +std/utilities/format/format.formatter/format.formatter.locking/enable_nonlocking_formatter_optimization.compile.pass.cpp FAIL + # *** MISSING COMPILER FEATURES *** # P1169R4 static operator() @@ -845,6 +840,8 @@ std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp FAIL # Not analyzed. Possible MSVC constexpr bug. # note: failure was caused by a read of a variable outside its lifetime +std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp:0 FAIL +std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp:1 FAIL std/containers/sequences/vector.bool/construct_iter_iter.pass.cpp:0 FAIL std/containers/sequences/vector.bool/construct_iter_iter.pass.cpp:1 FAIL std/containers/sequences/vector.bool/construct_iter_iter_alloc.pass.cpp:0 FAIL @@ -938,6 +935,7 @@ std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requir std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_piecewise_pair_evil.pass.cpp FAIL # Not analyzed, failing due to constexpr step limits. +std/algorithms/alg.nonmodifying/alg.contains/ranges.contains_subrange.pass.cpp:2 FAIL std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp FAIL std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp FAIL std/containers/sequences/vector.bool/append_range.pass.cpp FAIL @@ -1045,11 +1043,6 @@ std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.segmented. std/algorithms/alg.modifying.operations/alg.move/ranges.move.segmented.pass.cpp:0 FAIL std/algorithms/alg.modifying.operations/alg.move/ranges.move.segmented.pass.cpp:1 FAIL -# Not analyzed. constexpr evaluation fails with note: subobject '_Val' is not initialized -std/ranges/range.adaptors/range.join/end.pass.cpp:2 FAIL -std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.pass.cpp:2 FAIL -std/ranges/range.adaptors/range.join/range.join.sentinel/eq.pass.cpp:2 FAIL - # Not analyzed. constexpr evaluation fails with note: failure was caused by out of range index MEOW; allowed range is 0 <= index < 2 std/ranges/range.adaptors/range.join/adaptor.pass.cpp:0 FAIL std/ranges/range.adaptors/range.join/adaptor.pass.cpp:1 FAIL @@ -1241,10 +1234,6 @@ std/atomics/atomics.ref/operator_plus_equals.pass.cpp SKIPPED std/atomics/atomics.ref/store.pass.cpp SKIPPED std/atomics/atomics.ref/wait.pass.cpp SKIPPED -# Not analyzed. Attempting to dereference `void *`. -std/utilities/memory/unique.ptr/noexcept_operator_star.compile.pass.cpp FAIL -std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/dereference.single.pass.cpp FAIL - # Not analyzed. Attempting to delete `nullptr_t`. std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter.pass.cpp FAIL @@ -1268,6 +1257,12 @@ std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp FAIL # Clang assertion: std::hermite(n, +inf) == inf std/numerics/c.math/hermite.pass.cpp FAIL +# Not analyzed. Test coverage for LLVM-104496 uses span. +std/containers/views/views.span/span.cons/copy.pass.cpp FAIL + +# Not analyzed. LLVM-103409 added a test to verify that std::optional's internal constructors aren't visible to users. +std/utilities/optional/optional.object/optional.object.ctor/gh_101960_internal_ctor.compile.pass.cpp FAIL + # *** XFAILs WHICH PASS *** # These tests contain `// XFAIL: msvc` comments, which accurately describe runtime failures for x86 and x64. From 3705e3651a5c59c3ae79c6c7ff292486fef244d0 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 25 Aug 2024 10:30:58 -0700 Subject: [PATCH 03/42] Floating minmax: fix negative zero handling and dedicated test coverage for arrays of +0.0 and -0.0 only (#4734) Co-authored-by: Stephan T. Lavavej --- stl/inc/algorithm | 24 +++-- stl/inc/xutility | 30 ++++-- stl/src/vector_algorithms.cpp | 32 +++--- .../include/test_min_max_element_support.hpp | 13 +++ .../test_vector_algorithms_support.hpp | 64 +++++++++++ tests/std/test.lst | 1 + .../VSO_0000000_vector_algorithms/test.cpp | 98 ++--------------- .../env.lst | 57 ++++++++++ .../test.cpp | 102 ++++++++++++++++++ 9 files changed, 300 insertions(+), 121 deletions(-) create mode 100644 tests/std/include/test_vector_algorithms_support.hpp create mode 100644 tests/std/tests/VSO_0000000_vector_algorithms_floats/env.lst create mode 100644 tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp diff --git a/stl/inc/algorithm b/stl/inc/algorithm index a0c9712ed3d..60207ef2c6d 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -10203,7 +10203,7 @@ _NODISCARD constexpr pair<_Ty, _Ty> minmax(initializer_list<_Ty> _Ilist, _Pr _Pr _STL_ASSERT( _Ilist.size() != 0, "An initializer_list passed to std::minmax must not be empty. (N4971 [alg.min.max]/21)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (_Is_min_max_optimization_safe) { + if constexpr (_Is_min_max_value_optimization_safe) { if (!_STD _Is_constant_evaluated()) { const auto _Result = _STD _Minmax_vectorized(_Ilist.begin(), _Ilist.end()); return {static_cast<_Ty>(_Result._Min), static_cast<_Ty>(_Result._Max)}; @@ -10332,13 +10332,21 @@ namespace ranges { using _Vty = iter_value_t<_It>; #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (is_same_v<_Pj, identity> && _Is_min_max_optimization_safe<_It, _Pr> - && sized_sentinel_for<_Se, _It>) { - if (!_STD is_constant_evaluated()) { - const auto _First_ptr = _STD to_address(_First); - const auto _Last_ptr = _First_ptr + (_Last - _First); - const auto _Result = _STD _Minmax_vectorized(_First_ptr, _Last_ptr); - return {static_cast<_Vty>(_Result._Min), static_cast<_Vty>(_Result._Max)}; + if constexpr (is_same_v<_Pj, identity> && sized_sentinel_for<_Se, _It>) { + if constexpr (_Is_min_max_value_optimization_safe<_It, _Pr>) { + if (!_STD is_constant_evaluated()) { + const auto _First_ptr = _STD to_address(_First); + const auto _Last_ptr = _First_ptr + (_Last - _First); + const auto _Result = _STD _Minmax_vectorized(_First_ptr, _Last_ptr); + return {static_cast<_Vty>(_Result._Min), static_cast<_Vty>(_Result._Max)}; + } + } else if constexpr (_Is_min_max_optimization_safe<_It, _Pr>) { + if (!_STD is_constant_evaluated()) { + const auto _First_ptr = _STD to_address(_First); + const auto _Last_ptr = _First_ptr + (_Last - _First); + const auto _Result = _STD _Minmax_element_vectorized(_First_ptr, _Last_ptr); + return {*static_cast(_Result.first), *static_cast(_Result.second)}; + } } } #endif // _USE_STD_VECTOR_ALGORITHMS diff --git a/stl/inc/xutility b/stl/inc/xutility index 110178e1416..f6fe60bae2b 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -6801,6 +6801,24 @@ constexpr bool _Is_min_max_optimization_safe = // Activate the vector algorithms #endif // _HAS_CXX20 is_same<_Pr, less<>>, is_same<_Pr, less<_Elem>>>>; // predicate is less +// Unlike the position-based vectorized implementation, the value-based vectorized implementation +// does not always produce the expected results for floating-point types. +// +// Efficient vectorization needs to find the vertical minmax first, and then the horizontal one. +// This alters the order of comparison: index zero element is first compared against +// vector size equal index element and only in the end against index one element. +// With equivalent but distinguishable +0.0 and -0.0 values, the altered comparison order +// will not produce the expected result in some cases (will return +0.0 instead of -0.0 or the reverse). +// +// The result is still acceptable for /fp:fast when +0.0 / -0.0 are not expected to be properly distinguished, +// and the compiler itself takes advantage of it. +template > +constexpr bool _Is_min_max_value_optimization_safe = // Activate the vector algorithms for ranges::min/max? +#ifndef _M_FP_FAST + !is_floating_point_v<_Elem> && +#endif // ^^^ !defined(_M_FP_FAST) ^^^ + _Is_min_max_optimization_safe<_Iter, _Pr, _Elem>; + template constexpr _FwdIt _Max_element_unchecked(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { // find largest element #if _USE_STD_VECTOR_ALGORITHMS @@ -6931,7 +6949,7 @@ _NODISCARD constexpr _Ty(max)(initializer_list<_Ty> _Ilist, _Pr _Pred) { _STL_ASSERT( _Ilist.size() != 0, "An initializer_list passed to std::max must not be empty. (N4971 [alg.min.max]/13)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (_Is_min_max_optimization_safe) { + if constexpr (_Is_min_max_value_optimization_safe) { if (!_Is_constant_evaluated()) { return static_cast<_Ty>(_STD _Max_vectorized(_Ilist.begin(), _Ilist.end())); } @@ -6977,7 +6995,7 @@ namespace ranges { _STL_ASSERT(_First != _Last, "An initializer_list passed to std::ranges::max must not be empty. (N4971 [alg.min.max]/13)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (is_same_v<_Pj, identity> && _Is_min_max_optimization_safe) { + if constexpr (is_same_v<_Pj, identity> && _Is_min_max_value_optimization_safe) { if (!_STD is_constant_evaluated()) { return static_cast<_Ty>(_STD _Max_vectorized(_First, _Last)); } @@ -6996,7 +7014,7 @@ namespace ranges { _STL_ASSERT( _UFirst != _ULast, "A range passed to std::ranges::max must not be empty. (N4971 [alg.min.max]/13)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (is_same_v<_Pj, identity> && _Is_min_max_optimization_safe + if constexpr (is_same_v<_Pj, identity> && _Is_min_max_value_optimization_safe && sized_sentinel_for) { if (!_STD is_constant_evaluated()) { const auto _First_ptr = _STD to_address(_UFirst); @@ -7155,7 +7173,7 @@ _NODISCARD constexpr _Ty(min)(initializer_list<_Ty> _Ilist, _Pr _Pred) { _STL_ASSERT( _Ilist.size() != 0, "An initializer_list passed to std::min must not be empty. (N4971 [alg.min.max]/5)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (_Is_min_max_optimization_safe) { + if constexpr (_Is_min_max_value_optimization_safe) { if (!_Is_constant_evaluated()) { return static_cast<_Ty>(_STD _Min_vectorized(_Ilist.begin(), _Ilist.end())); } @@ -7195,7 +7213,7 @@ namespace ranges { _STL_ASSERT(_First != _Last, "An initializer_list passed to std::ranges::min must not be empty. (N4971 [alg.min.max]/5)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (is_same_v<_Pj, identity> && _Is_min_max_optimization_safe) { + if constexpr (is_same_v<_Pj, identity> && _Is_min_max_value_optimization_safe) { if (!_STD is_constant_evaluated()) { return static_cast<_Ty>(_STD _Min_vectorized(_First, _Last)); } @@ -7214,7 +7232,7 @@ namespace ranges { _STL_ASSERT( _UFirst != _ULast, "A range passed to std::ranges::min must not be empty. (N4971 [alg.min.max]/5)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (is_same_v<_Pj, identity> && _Is_min_max_optimization_safe + if constexpr (is_same_v<_Pj, identity> && _Is_min_max_value_optimization_safe && sized_sentinel_for) { if (!_STD is_constant_evaluated()) { const auto _First_ptr = _STD to_address(_UFirst); diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index 44cca169203..8d57d7df204 100644 --- a/stl/src/vector_algorithms.cpp +++ b/stl/src/vector_algorithms.cpp @@ -1415,8 +1415,8 @@ namespace { template static __m128 _H_func(const __m128 _Cur, _Fn _Funct) noexcept { __m128 _H_min_val = _Cur; - _H_min_val = _Funct(_H_min_val, _mm_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(1, 0, 3, 2))); - _H_min_val = _Funct(_H_min_val, _mm_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(2, 3, 0, 1))); + _H_min_val = _Funct(_mm_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(2, 3, 0, 1)), _H_min_val); + _H_min_val = _Funct(_mm_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(1, 0, 3, 2)), _H_min_val); return _H_min_val; } @@ -1457,11 +1457,11 @@ namespace { } static __m128 _Min(const __m128 _First, const __m128 _Second, __m128 = _mm_undefined_ps()) noexcept { - return _mm_min_ps(_First, _Second); + return _mm_min_ps(_Second, _First); } static __m128 _Max(const __m128 _First, const __m128 _Second, __m128 = _mm_undefined_ps()) noexcept { - return _mm_max_ps(_First, _Second); + return _mm_max_ps(_Second, _First); } static __m128i _Mask_cast(const __m128 _Mask) noexcept { @@ -1485,9 +1485,9 @@ namespace { template static __m256 _H_func(const __m256 _Cur, _Fn _Funct) noexcept { __m256 _H_min_val = _Cur; - _H_min_val = _Funct(_H_min_val, _mm256_permute2f128_ps(_H_min_val, _mm256_undefined_ps(), 0x01)); - _H_min_val = _Funct(_H_min_val, _mm256_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(1, 0, 3, 2))); - _H_min_val = _Funct(_H_min_val, _mm256_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(2, 3, 0, 1))); + _H_min_val = _Funct(_mm256_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(2, 3, 0, 1)), _H_min_val); + _H_min_val = _Funct(_mm256_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(1, 0, 3, 2)), _H_min_val); + _H_min_val = _Funct(_mm256_permute2f128_ps(_H_min_val, _mm256_undefined_ps(), 0x01), _H_min_val); return _H_min_val; } @@ -1528,11 +1528,11 @@ namespace { } static __m256 _Min(const __m256 _First, const __m256 _Second, __m256 = _mm256_undefined_ps()) noexcept { - return _mm256_min_ps(_First, _Second); + return _mm256_min_ps(_Second, _First); } static __m256 _Max(const __m256 _First, const __m256 _Second, __m256 = _mm256_undefined_ps()) noexcept { - return _mm256_max_ps(_First, _Second); + return _mm256_max_ps(_Second, _First); } static __m256i _Mask_cast(const __m256 _Mask) noexcept { @@ -1575,7 +1575,7 @@ namespace { template static __m128d _H_func(const __m128d _Cur, _Fn _Funct) noexcept { __m128d _H_min_val = _Cur; - _H_min_val = _Funct(_H_min_val, _mm_shuffle_pd(_H_min_val, _H_min_val, 1)); + _H_min_val = _Funct(_mm_shuffle_pd(_H_min_val, _H_min_val, 1), _H_min_val); return _H_min_val; } @@ -1615,11 +1615,11 @@ namespace { } static __m128d _Min(const __m128d _First, const __m128d _Second, __m128d = _mm_undefined_pd()) noexcept { - return _mm_min_pd(_First, _Second); + return _mm_min_pd(_Second, _First); } static __m128d _Max(const __m128d _First, const __m128d _Second, __m128d = _mm_undefined_pd()) noexcept { - return _mm_max_pd(_First, _Second); + return _mm_max_pd(_Second, _First); } static __m128i _Mask_cast(const __m128d _Mask) noexcept { @@ -1643,8 +1643,8 @@ namespace { template static __m256d _H_func(const __m256d _Cur, _Fn _Funct) noexcept { __m256d _H_min_val = _Cur; - _H_min_val = _Funct(_H_min_val, _mm256_permute4x64_pd(_H_min_val, _MM_SHUFFLE(1, 0, 3, 2))); - _H_min_val = _Funct(_H_min_val, _mm256_shuffle_pd(_H_min_val, _H_min_val, 0b0101)); + _H_min_val = _Funct(_mm256_shuffle_pd(_H_min_val, _H_min_val, 0b0101), _H_min_val); + _H_min_val = _Funct(_mm256_permute4x64_pd(_H_min_val, _MM_SHUFFLE(1, 0, 3, 2)), _H_min_val); return _H_min_val; } @@ -1685,11 +1685,11 @@ namespace { } static __m256d _Min(const __m256d _First, const __m256d _Second, __m256d = _mm256_undefined_pd()) noexcept { - return _mm256_min_pd(_First, _Second); + return _mm256_min_pd(_Second, _First); } static __m256d _Max(const __m256d _First, const __m256d _Second, __m256d = _mm256_undefined_pd()) noexcept { - return _mm256_max_pd(_First, _Second); + return _mm256_max_pd(_Second, _First); } static __m256i _Mask_cast(const __m256d _Mask) noexcept { diff --git a/tests/std/include/test_min_max_element_support.hpp b/tests/std/include/test_min_max_element_support.hpp index a717c7ef85f..621c76fe960 100644 --- a/tests/std/include/test_min_max_element_support.hpp +++ b/tests/std/include/test_min_max_element_support.hpp @@ -5,7 +5,9 @@ #include #include +#include #include +#include #include #include @@ -116,6 +118,17 @@ void test_case_min_max_element(const std::vector& input) { assert(*expected_max == actual_max_value); assert(*expected_minmax.first == actual_minmax_value.min); assert(*expected_minmax.second == actual_minmax_value.max); + +#ifndef _M_FP_FAST + // With /fp:fast mode the compiler does not try to produce the code that correctly + // distinguishes +0.0 and -0.0, so the algorithms are not expected to either. + if constexpr (std::is_floating_point_v) { + assert(std::signbit(*expected_min) == std::signbit(actual_min_value)); + assert(std::signbit(*expected_max) == std::signbit(actual_max_value)); + assert(std::signbit(*expected_minmax.first) == std::signbit(actual_minmax_value.min)); + assert(std::signbit(*expected_minmax.second) == std::signbit(actual_minmax_value.max)); + } +#endif // !defined(_M_FP_FAST) } #endif // _HAS_CXX20 } diff --git a/tests/std/include/test_vector_algorithms_support.hpp b/tests/std/include/test_vector_algorithms_support.hpp new file mode 100644 index 00000000000..5cdffd9ffe4 --- /dev/null +++ b/tests/std/include/test_vector_algorithms_support.hpp @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +inline void initialize_randomness(std::mt19937_64& gen) { + constexpr std::size_t n = std::mt19937_64::state_size; + constexpr std::size_t w = std::mt19937_64::word_size; + static_assert(w % 32 == 0, "w should be evenly divisible by 32"); + constexpr std::size_t k = w / 32; + + std::vector vec(n * k); + + std::random_device rd; + std::generate(vec.begin(), vec.end(), std::ref(rd)); + + std::printf("This is a randomized test.\n"); + std::printf("DO NOT IGNORE/RERUN ANY FAILURES.\n"); + std::printf("You must report them to the STL maintainers.\n\n"); + + std::printf("Seed vector: "); + for (const auto& e : vec) { + std::printf("%u,", e); + } + std::printf("\n"); + + std::seed_seq seq(vec.cbegin(), vec.cend()); + gen.seed(seq); +} + +#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) +extern "C" long __isa_enabled; + +inline void disable_instructions(ISA_AVAILABILITY isa) { + __isa_enabled &= ~(1UL << static_cast(isa)); +} +#endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) + +constexpr std::size_t dataCount = 1024; + +template +void run_randomized_tests_with_different_isa_levels(TestFunc tests) { + std::mt19937_64 gen; + initialize_randomness(gen); + + tests(gen); + +#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) + disable_instructions(__ISA_AVAILABLE_AVX2); + tests(gen); + + disable_instructions(__ISA_AVAILABLE_SSE42); + tests(gen); +#endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) +} diff --git a/tests/std/test.lst b/tests/std/test.lst index f75a8adcd78..7dda49e7f12 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -709,6 +709,7 @@ tests\VSO_0000000_regex_use tests\VSO_0000000_string_view_idl tests\VSO_0000000_type_traits tests\VSO_0000000_vector_algorithms +tests\VSO_0000000_vector_algorithms_floats tests\VSO_0000000_wcfb01_idempotent_container_destructors tests\VSO_0000000_wchar_t_filebuf_xsmeown tests\VSO_0095468_clr_exception_ptr_bad_alloc diff --git a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp index 5a7a1520412..1e8e501e50d 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp @@ -4,13 +4,12 @@ #include #include #include +#include #include #include -#include #include #include #include -#include #include #include #include @@ -25,49 +24,10 @@ #endif // _HAS_CXX20 #include "test_min_max_element_support.hpp" +#include "test_vector_algorithms_support.hpp" using namespace std; -#pragma warning(disable : 4984) // 'if constexpr' is a C++17 language extension -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wc++17-extensions" // constexpr if is a C++17 extension -#endif // __clang__ - -void initialize_randomness(mt19937_64& gen) { - constexpr size_t n = mt19937_64::state_size; - constexpr size_t w = mt19937_64::word_size; - static_assert(w % 32 == 0, "w should be evenly divisible by 32"); - constexpr size_t k = w / 32; - - vector vec(n * k); - - random_device rd; - generate(vec.begin(), vec.end(), ref(rd)); - - printf("This is a randomized test.\n"); - printf("DO NOT IGNORE/RERUN ANY FAILURES.\n"); - printf("You must report them to the STL maintainers.\n\n"); - - printf("Seed vector: "); - for (const auto& e : vec) { - printf("%u,", e); - } - printf("\n"); - - seed_seq seq(vec.cbegin(), vec.cend()); - gen.seed(seq); -} - -#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) -extern "C" long __isa_enabled; - -void disable_instructions(ISA_AVAILABILITY isa) { - __isa_enabled &= ~(1UL << static_cast(isa)); -} -#endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) - -constexpr size_t dataCount = 1024; - template ptrdiff_t last_known_good_count(FwdIt first, FwdIt last, T v) { ptrdiff_t result = 0; @@ -391,31 +351,6 @@ void test_min_max_element(mt19937_64& gen) { } } -template -void test_min_max_element_floating(mt19937_64& gen) { - normal_distribution dis(-100000.0, 100000.0); - - constexpr auto input_of_input_size = dataCount / 2; - vector input_of_input(input_of_input_size); - input_of_input[0] = -numeric_limits::infinity(); - input_of_input[1] = +numeric_limits::infinity(); - input_of_input[2] = -0.0; - input_of_input[3] = +0.0; - for (size_t i = 4; i < input_of_input_size; ++i) { - input_of_input[i] = dis(gen); - } - - uniform_int_distribution idx_dis(0, input_of_input_size - 1); - - vector input; - input.reserve(dataCount); - test_case_min_max_element(input); - for (size_t attempts = 0; attempts < dataCount; ++attempts) { - input.push_back(input_of_input[idx_dis(gen)]); - test_case_min_max_element(input); - } -} - void test_min_max_element_pointers(mt19937_64& gen) { const short arr[20]{}; @@ -901,10 +836,6 @@ void test_vector_algorithms(mt19937_64& gen) { test_min_max_element(gen); test_min_max_element(gen); - test_min_max_element_floating(gen); - test_min_max_element_floating(gen); - test_min_max_element_floating(gen); - test_min_max_element_pointers(gen); test_min_max_element_special_cases(); // SSE2 vectors @@ -1161,24 +1092,9 @@ int main() { #if _HAS_CXX20 assert(test_constexpr()); #endif // _HAS_CXX20 - - mt19937_64 gen; - initialize_randomness(gen); - - test_vector_algorithms(gen); - test_various_containers(); - test_bitset(gen); -#ifndef _M_CEE_PURE -#if defined(_M_IX86) || defined(_M_X64) - disable_instructions(__ISA_AVAILABLE_AVX2); - test_vector_algorithms(gen); - test_various_containers(); - test_bitset(gen); - - disable_instructions(__ISA_AVAILABLE_SSE42); - test_vector_algorithms(gen); - test_various_containers(); - test_bitset(gen); -#endif // defined(_M_IX86) || defined(_M_X64) -#endif // _M_CEE_PURE + run_randomized_tests_with_different_isa_levels([](mt19937_64& gen) { + test_vector_algorithms(gen); + test_various_containers(); + test_bitset(gen); + }); } diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_floats/env.lst b/tests/std/tests/VSO_0000000_vector_algorithms_floats/env.lst new file mode 100644 index 00000000000..b8b3805e451 --- /dev/null +++ b/tests/std/tests/VSO_0000000_vector_algorithms_floats/env.lst @@ -0,0 +1,57 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\prefix.lst +RUNALL_CROSSLIST +# Copied from ..\usual_matrix.lst, /fp options excluded, /clr and /clr:pure lines dropped +PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++14 /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MD /std:c++14 /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++17 /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MD /std:c++17 /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++20 /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MD /std:c++20 /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- /Zc:noexceptTypes-" +ASAN PM_CL="/EHsc /MD /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- /Zc:noexceptTypes- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /Zc:char8_t- /w14640 /Zc:threadSafeInit- /Zc:preprocessor" +ASAN PM_CL="/EHsc /MD /std:c++latest /permissive- /Zc:char8_t- /Zc:preprocessor /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MDd /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /Zc:wchar_t- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MDd /std:c++latest /permissive- /Zc:wchar_t- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MDd /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MDd /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MDd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++14 /w14640 /Zc:threadSafeInit- /Zc:preprocessor" +ASAN PM_CL="/EHsc /MDd /std:c++14 /w14640 /Zc:threadSafeInit- /Zc:preprocessor -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MDd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++17 /permissive- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MDd /std:c++17 /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MDd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++20 /permissive- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MDd /std:c++20 /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MT /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MT /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MT /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /analyze:only /analyze:autolog- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MT /std:c++latest /permissive- /analyze:only /analyze:autolog- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MT /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive- /w14640 /Zc:threadSafeInit-" +# No corresponding ASAN config, since the above differs from another config only in IDL +PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MTd /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MTd /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MTd /std:c++latest /permissive /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive- /analyze:only /analyze:autolog- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MTd /std:c++latest /permissive- /analyze:only /analyze:autolog- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/BE /c /EHsc /MD /std:c++14 /w14640 /Zc:threadSafeInit-" +PM_CL="/BE /c /EHsc /MDd /std:c++17 /permissive- /w14640 /Zc:threadSafeInit-" +PM_CL="/BE /c /EHsc /MT /std:c++20 /permissive- /w14640 /Zc:threadSafeInit-" +PM_CL="/BE /c /EHsc /MTd /std:c++latest /permissive- /w14640 /Zc:threadSafeInit-" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MD /std:c++14 /w14640 /Zc:threadSafeInit- --start-no-unused-arguments" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MDd /std:c++17 /w14640 /Zc:threadSafeInit- --start-no-unused-arguments" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MT /std:c++20 /permissive- /w14640 /Zc:threadSafeInit- --start-no-unused-arguments" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MTd /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- --start-no-unused-arguments" +# TRANSITION, GH-3568 +# PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MT /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=undefined -fno-sanitize-recover=undefined --start-no-unused-arguments" +RUNALL_CROSSLIST +* PM_CL="/fp:strict" +* PM_CL="/fp:precise" +* PM_CL="/fp:fast" +RUNALL_CROSSLIST +* PM_CL="" # Test default setting +* PM_CL="/D_USE_STD_VECTOR_ALGORITHMS=0" # Test escape hatch, see GH-1751 diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp new file mode 100644 index 00000000000..c43d6a2a5b1 --- /dev/null +++ b/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#include "test_min_max_element_support.hpp" +#include "test_vector_algorithms_support.hpp" + +using namespace std; + +template +void test_min_max_element_floating_with_values(mt19937_64& gen, const vector& input_of_input) { + uniform_int_distribution idx_dis(0, input_of_input.size() - 1); + + vector input; + input.reserve(dataCount); + test_case_min_max_element(input); + for (size_t attempts = 0; attempts < dataCount; ++attempts) { + input.push_back(input_of_input[idx_dis(gen)]); + test_case_min_max_element(input); + } +} + +template +void test_min_max_element_floating_any(mt19937_64& gen) { + normal_distribution dis(-100000.0, 100000.0); + + constexpr auto input_of_input_size = dataCount / 2; + vector input_of_input(input_of_input_size); + input_of_input[0] = -numeric_limits::infinity(); + input_of_input[1] = +numeric_limits::infinity(); + input_of_input[2] = -0.0; + input_of_input[3] = +0.0; + for (size_t i = 4; i < input_of_input_size; ++i) { + input_of_input[i] = dis(gen); + } + + test_min_max_element_floating_with_values(gen, input_of_input); +} + +template +void test_min_max_element_floating_zero(mt19937_64& gen) { + test_min_max_element_floating_with_values(gen, {-0.0, +0.0}); + test_min_max_element_floating_with_values(gen, {-0.0, +0.0, +1.0}); + test_min_max_element_floating_with_values(gen, {-0.0, +0.0, -1.0}); +} + +template +void test_min_max_element_floating_zero_predef() { + for (size_t len = 2; len != 16; ++len) { + for (size_t pos = 0; pos != len; ++pos) { + vector v(len, +0.0); + v[pos] = -0.0; + test_case_min_max_element(v); + + for (size_t i = 0; i != pos; ++i) { + v[i] = +1.0; + } + + test_case_min_max_element(v); + + for (size_t i = 0; i != pos; ++i) { + v[i] = -1.0; + } + + test_case_min_max_element(v); + + for (size_t i = 0; i != pos; ++i) { + v[i] = +0.0; + } + + for (size_t i = pos + 1; i != len; ++i) { + v[i] = +1.0; + } + + test_case_min_max_element(v); + + for (size_t i = pos + 1; i != len; ++i) { + v[i] = -1.0; + } + } + } +} + +template +void test_min_max_element_floating(mt19937_64& gen) { + test_min_max_element_floating_any(gen); + test_min_max_element_floating_zero(gen); + test_min_max_element_floating_zero_predef(); +} + +void test_vector_algorithms(mt19937_64& gen) { + test_min_max_element_floating(gen); + test_min_max_element_floating(gen); +} + +int main() { + run_randomized_tests_with_different_isa_levels(test_vector_algorithms); +} From 587728188f4e75442cc87aaabca74d8ea6181de2 Mon Sep 17 00:00:00 2001 From: Nikolay Baklicharov Date: Sun, 25 Aug 2024 20:41:00 +0300 Subject: [PATCH 04/42] Fix put_time() crash on invalid struct tm data (#4883) Co-authored-by: Stephan T. Lavavej --- stl/inc/xloctime | 127 +++++++++++++++++- .../std/tests/Dev11_0836436_get_time/test.cpp | 93 +++++++------ 2 files changed, 179 insertions(+), 41 deletions(-) diff --git a/stl/inc/xloctime b/stl/inc/xloctime index 6926937743d..1952685dddc 100644 --- a/stl/inc/xloctime +++ b/stl/inc/xloctime @@ -666,6 +666,115 @@ _NODISCARD constexpr bool _Is_valid_strftime_specifier(const char _Specifier) { return false; } +_NODISCARD constexpr bool _Is_valid_strftime_tm_sec(const tm* const _Pt) noexcept { + // seconds after the minute - [0, 60] including leap second + return _Pt->tm_sec >= 0 && _Pt->tm_sec <= 60; +} + +_NODISCARD constexpr bool _Is_valid_strftime_tm_min(const tm* const _Pt) noexcept { + // minutes after the hour - [0, 59] + return _Pt->tm_min >= 0 && _Pt->tm_min <= 59; +} + +_NODISCARD constexpr bool _Is_valid_strftime_tm_hour(const tm* const _Pt) noexcept { + // hours since midnight - [0, 23] + return _Pt->tm_hour >= 0 && _Pt->tm_hour <= 23; +} + +_NODISCARD constexpr bool _Is_valid_strftime_tm_mday(const tm* const _Pt) noexcept { + // day of the month - [1, 31] + return _Pt->tm_mday >= 1 && _Pt->tm_mday <= 31; +} + +_NODISCARD constexpr bool _Is_valid_strftime_tm_mon(const tm* const _Pt) noexcept { + // months since January - [0, 11] + return _Pt->tm_mon >= 0 && _Pt->tm_mon <= 11; +} + +_NODISCARD constexpr bool _Is_valid_strftime_tm_year(const tm* const _Pt) noexcept { + // years since 1900 - UCRT max range is up until 8099 + return _Pt->tm_year >= -1900 && _Pt->tm_year <= 8099; +} + +_NODISCARD constexpr bool _Is_valid_strftime_tm_wday(const tm* const _Pt) noexcept { + // days since Sunday - [0, 6] + return _Pt->tm_wday >= 0 && _Pt->tm_wday <= 6; +} + +_NODISCARD constexpr bool _Is_valid_strftime_tm_yday(const tm* const _Pt) noexcept { + // days since January 1 - [0, 365] + return _Pt->tm_yday >= 0 && _Pt->tm_yday <= 365; +} + +_NODISCARD constexpr bool _Is_valid_strftime_tm_data(const char _Specifier, const tm* const _Pt) noexcept { + if (!_Pt) { + return false; + } + + switch (_Specifier) { + case 'S': + return _Is_valid_strftime_tm_sec(_Pt); + case 'M': + return _Is_valid_strftime_tm_min(_Pt); + case 'H': + case 'I': + case 'p': + return _Is_valid_strftime_tm_hour(_Pt); + case 'd': + case 'e': + return _Is_valid_strftime_tm_mday(_Pt); + case 'b': + case 'B': + case 'm': + case 'h': + return _Is_valid_strftime_tm_mon(_Pt); + case 'C': + case 'y': + case 'Y': + return _Is_valid_strftime_tm_year(_Pt); + case 'j': + return _Is_valid_strftime_tm_yday(_Pt); + case 'a': + case 'A': + case 'u': + case 'w': + return _Is_valid_strftime_tm_wday(_Pt); + case 'U': // C23 7.29.3.5 "The strftime function"/3 says that %U and %W depend on tm_year, + case 'W': // but the UCRT neither uses nor validates it. + return _Is_valid_strftime_tm_wday(_Pt) && _Is_valid_strftime_tm_yday(_Pt); + case 'R': + return _Is_valid_strftime_tm_hour(_Pt) && _Is_valid_strftime_tm_min(_Pt); + case 'D': + case 'x': + case 'F': + return _Is_valid_strftime_tm_year(_Pt) && _Is_valid_strftime_tm_mon(_Pt) && _Is_valid_strftime_tm_mday(_Pt); + case 'g': + case 'G': + return _Is_valid_strftime_tm_year(_Pt) && _Is_valid_strftime_tm_wday(_Pt) && _Is_valid_strftime_tm_yday(_Pt); + case 'r': + case 'X': + case 'T': + return _Is_valid_strftime_tm_hour(_Pt) && _Is_valid_strftime_tm_min(_Pt) && _Is_valid_strftime_tm_sec(_Pt); + case 'c': + return _Is_valid_strftime_tm_wday(_Pt) && _Is_valid_strftime_tm_mon(_Pt) && _Is_valid_strftime_tm_mday(_Pt) + && _Is_valid_strftime_tm_hour(_Pt) && _Is_valid_strftime_tm_min(_Pt) && _Is_valid_strftime_tm_sec(_Pt) + && _Is_valid_strftime_tm_year(_Pt); + case 'V': // C23 7.29.3.5 "The strftime function"/3 says that %V depends on tm_year, tm_wday, and tm_yday. + // The UCRT uses them without validating them. + return true; + case 'z': // C23 7.29.3.5 "The strftime function"/3 says that %z and %Z depend on tm_isdst. + case 'Z': // The UCRT treats it as a boolean value, so there's no need for validation. + return true; + case 'n': // newline + case 't': // tab + return true; + default: + // We should have handled %% and called _Is_valid_strftime_specifier() before calling this function. + _STL_INTERNAL_CHECK(false); + return false; + } +} + _EXPORT_STD extern "C++" template >> class time_put : public locale::facet { // facet for converting encoded times to text public: @@ -713,7 +822,11 @@ public: } *_Dest++ = _Specifier; } else { - _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field + if (_Is_valid_strftime_tm_data(_Specifier, _Pt)) { + _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field + } else { + *_Dest++ = _Elem('?'); + } } } } @@ -849,7 +962,11 @@ public: } *_Dest++ = *_Fmtfirst; } else { - _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field + if (_Is_valid_strftime_tm_data(_Specifier, _Pt)) { + _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field + } else { + *_Dest++ = _Elem('?'); + } } } } @@ -994,7 +1111,11 @@ public: } *_Dest++ = *_Fmtfirst; } else { - _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field + if (_Is_valid_strftime_tm_data(_Specifier, _Pt)) { + _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field + } else { + *_Dest++ = _Elem('?'); + } } } } diff --git a/tests/std/tests/Dev11_0836436_get_time/test.cpp b/tests/std/tests/Dev11_0836436_get_time/test.cpp index ce5152ca1c9..6c05df8bd3f 100644 --- a/tests/std/tests/Dev11_0836436_get_time/test.cpp +++ b/tests/std/tests/Dev11_0836436_get_time/test.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include #include #include @@ -106,11 +107,11 @@ void test_DevDiv_990695(); void test_locale_russian(); void test_locale_german(); void test_locale_chinese(); -void test_invalid_argument(); void test_buffer_resizing(); void test_gh_2618(); void test_gh_2848(); void test_gh_4820(); +void test_gh_4882(); int main() { assert(read_hour("12 AM") == 0); @@ -154,11 +155,11 @@ int main() { test_locale_russian(); test_locale_german(); test_locale_chinese(); - test_invalid_argument(); test_buffer_resizing(); test_gh_2618(); test_gh_2848(); test_gh_4820(); + test_gh_4882(); } typedef istreambuf_iterator Iter; @@ -774,42 +775,6 @@ void test_locale_chinese() { assert(read_date_locale(L"2020-\x0031\x0032\x6708-31", "zh-CN") == make_tuple(31, 11, 120)); } -void test_invalid_parameter_handler(const wchar_t* const expression, const wchar_t* const function, - const wchar_t* const file, const unsigned int line, const uintptr_t reserved) { - (void) expression; - (void) reserved; - - static int num_called = 0; - if (++num_called > 10) { - wprintf( - L"Test Failed: Invalid parameter handler was called over 10 times by %s in %s:%u\n", function, file, line); - exit(1); - } -} - -void test_invalid_argument() { -#ifndef _M_CEE_PURE - _set_invalid_parameter_handler(test_invalid_parameter_handler); - - time_t t = time(nullptr); - tm currentTime; - localtime_s(¤tTime, &t); - currentTime.tm_hour = 25; // set invalid hour - - { - wstringstream wss; - wss << put_time(¤tTime, L"%Y-%m-%d-%H-%M"); - assert(wss.rdstate() == ios_base::badbit); - } - - { - stringstream ss; - ss << put_time(¤tTime, "%Y-%m-%d-%H-%M"); - assert(ss.rdstate() == ios_base::badbit); - } -#endif // _M_CEE_PURE -} - void test_buffer_resizing() { time_t t = time(nullptr); tm currentTime; @@ -944,3 +909,55 @@ void test_gh_4820() { assert(wss.str() == L"\x043a%\x043e%\x0448%E\x043a%O\x0430"); } } + +void test_gh_4882() { + // GH-4882 : std::put_time should not crash on invalid/out-of-range tm struct values + const auto fieldValidation = [](int tm::*const field, const int value, const string& fmt) { + time_t t = time(nullptr); + tm currentTime; + localtime_s(¤tTime, &t); + + currentTime.*field = value; + + stringstream ss; + ss << put_time(¤tTime, fmt.c_str()); + assert(ss.rdstate() == ios_base::goodbit); + const auto result = ss.str(); + assert(result.size() == fmt.size() / 2); + assert(all_of(result.cbegin(), result.cend(), [](const char c) { return c == '?'; })); + + // Narrow conversion is good enough for our ASCII only format strings + wstring wfmt(fmt.size(), L' '); + transform(fmt.cbegin(), fmt.cend(), wfmt.begin(), [](const char c) { return static_cast(c); }); + + wstringstream wss; + wss << put_time(¤tTime, wfmt.c_str()); + assert(wss.rdstate() == ios_base::goodbit); + const auto wresult = wss.str(); + assert(wresult.size() == fmt.size() / 2); + assert(all_of(wresult.cbegin(), wresult.cend(), [](const wchar_t c) { return c == L'?'; })); + }; + + struct FormatTestData { + int tm::*field; + int lo; + int hi; + string fmt; + }; + + const FormatTestData testDataList[] = { + {&tm::tm_sec, -1, 61, "%S%r%X%T%c"}, + {&tm::tm_min, -1, 60, "%M%R%r%X%T%c"}, + {&tm::tm_hour, -1, 24, "%H%I%p%R%r%X%T%c"}, + {&tm::tm_mday, 0, 32, "%d%e%D%x%F%c"}, + {&tm::tm_mon, -1, 12, "%b%B%m%h%D%x%F%c"}, + {&tm::tm_year, -1901, 8100, "%C%y%Y%D%x%F%g%G%c"}, + {&tm::tm_wday, -1, 7, "%a%A%u%w%U%W%g%G%c"}, + {&tm::tm_yday, -1, 366, "%j%U%W%g%G"}, + }; + + for (const auto& testData : testDataList) { + fieldValidation(testData.field, testData.lo, testData.fmt); + fieldValidation(testData.field, testData.hi, testData.fmt); + } +} From f3567b8ae385676d6f54a8a885376b4fb63330f7 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 25 Aug 2024 10:52:27 -0700 Subject: [PATCH 05/42] Use `wmemchr` in optimizations (#4894) Co-authored-by: Stephan T. Lavavej --- stl/inc/xutility | 42 ++++++++++++++++++++++++----------- stl/src/vector_algorithms.cpp | 4 ++-- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index f6fe60bae2b..9097c517735 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -12,6 +12,7 @@ #include #include #include +#include #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) @@ -6009,17 +6010,27 @@ _NODISCARD _CONSTEXPR20 _InIt _Find_unchecked(_InIt _First, const _InIt _Last, c return _First + (_Result - _First_ptr); } #else // ^^^ _USE_STD_VECTOR_ALGORITHMS / !_USE_STD_VECTOR_ALGORITHMS vvv - if constexpr (sizeof(_Iter_value_t<_InIt>) == 1) { + if constexpr (sizeof(_Iter_value_t<_InIt>) <= 2) { const auto _First_ptr = _STD _To_address(_First); - const auto _Result = static_cast>*>( - _CSTD memchr(_First_ptr, static_cast(_Val), static_cast(_Last - _First))); + const auto _Count = static_cast(_Last - _First); + + using _Ptr_t = remove_reference_t<_Iter_ref_t<_InIt>>*; + _Ptr_t _Result; + + if constexpr (sizeof(_Iter_value_t<_InIt>) == 1) { + _Result = static_cast<_Ptr_t>(_CSTD memchr(_First_ptr, static_cast(_Val), _Count)); + } else { + _STL_INTERNAL_STATIC_ASSERT(sizeof(_Iter_value_t<_InIt>) == 2); + _Result = reinterpret_cast<_Ptr_t>(const_cast(_CSTD wmemchr( + reinterpret_cast(_First_ptr), static_cast(_Val), _Count))); + } + if constexpr (is_pointer_v<_InIt>) { return _Result ? _Result : _Last; } else { return _Result ? _First + (_Result - _First_ptr) : _Last; } } - // TRANSITION, DevCom-1614562: not trying wmemchr #endif // ^^^ !_USE_STD_VECTOR_ALGORITHMS ^^^ } } @@ -6062,14 +6073,12 @@ namespace ranges { template _Se, class _Ty, class _Pj = identity> requires indirect_binary_predicate, const _Ty*> _NODISCARD constexpr _It _Find_unchecked(_It _First, const _Se _Last, const _Ty& _Val, _Pj _Proj = {}) { - // TRANSITION, DevCom-1614562: not trying wmemchr - // Only single-byte elements are suitable for unsized optimization - constexpr bool _Single_byte_elements = sizeof(_Iter_value_t<_It>) == 1; - constexpr bool _Is_sized = sized_sentinel_for<_Se, _It>; + constexpr bool _Elements_are_1_or_2_bytes = sizeof(_Iter_value_t<_It>) <= 2; + constexpr bool _Is_sized = sized_sentinel_for<_Se, _It>; if constexpr (_Vector_alg_in_find_is_safe<_It, _Ty> - && (_Single_byte_elements ? _Is_sized || same_as<_Se, unreachable_sentinel_t> - : _Is_sized && _USE_STD_VECTOR_ALGORITHMS) + && (_Elements_are_1_or_2_bytes ? _Is_sized || same_as<_Se, unreachable_sentinel_t> + : _Is_sized && _USE_STD_VECTOR_ALGORITHMS) && same_as<_Pj, identity>) { if (!_STD is_constant_evaluated()) { if (!_STD _Could_compare_equal_to_value_type<_It>(_Val)) { @@ -6087,13 +6096,13 @@ namespace ranges { _Ptr_t _Result; #if _USE_STD_VECTOR_ALGORITHMS if constexpr (_Is_sized) { - // When _Is_sized && _Single_byte_elements, prefer this over memchr() for performance + // When _Is_sized && _Elements_are_1_or_2_bytes, prefer this over memchr()/wmemchr() for performance const auto _Last_ptr = _First_ptr + (_Last - _First); _Result = _STD _Find_vectorized(_First_ptr, _Last_ptr, _Val); } else #endif // ^^^ _USE_STD_VECTOR_ALGORITHMS ^^^ { - _STL_INTERNAL_STATIC_ASSERT(_Single_byte_elements); + _STL_INTERNAL_STATIC_ASSERT(_Elements_are_1_or_2_bytes); size_t _Count; if constexpr (_Is_sized) { _Count = static_cast(_Last - _First); @@ -6101,7 +6110,14 @@ namespace ranges { _Count = SIZE_MAX; } - _Result = static_cast<_Ptr_t>(_CSTD memchr(_First_ptr, static_cast(_Val), _Count)); + if constexpr (sizeof(_Iter_value_t<_It>) == 1) { + _Result = + static_cast<_Ptr_t>(_CSTD memchr(_First_ptr, static_cast(_Val), _Count)); + } else { + _STL_INTERNAL_STATIC_ASSERT(sizeof(_Iter_value_t<_It>) == 2); + _Result = reinterpret_cast<_Ptr_t>(const_cast(_CSTD wmemchr( + reinterpret_cast(_First_ptr), static_cast(_Val), _Count))); + } if constexpr (_Is_sized) { if (_Result == nullptr) { diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index 8d57d7df204..c86b96871f9 100644 --- a/stl/src/vector_algorithms.cpp +++ b/stl/src/vector_algorithms.cpp @@ -9,6 +9,7 @@ #include <__msvc_minmax.hpp> #include #include +#include #include #ifndef _M_ARM64EC @@ -3271,8 +3272,7 @@ const void* __stdcall __std_find_trivial_unsized_1(const void* const _First, con // TRANSITION, ABI: preserved for binary compatibility const void* __stdcall __std_find_trivial_unsized_2(const void* const _First, const uint16_t _Val) noexcept { - // TRANSITION, DevCom-1614562: not trying wmemchr - return __std_find_trivial_unsized_impl(_First, _Val); + return wmemchr(static_cast(_First), static_cast(_Val), SIZE_MAX); } // TRANSITION, ABI: preserved for binary compatibility From 20a1c9f0d2c5db3df52dfec88116999348439c09 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 26 Aug 2024 02:01:16 +0800 Subject: [PATCH 06/42] Test LWG-4105 `ranges::ends_with`'s Returns misses difference casting (#4897) Co-authored-by: Stephan T. Lavavej --- tests/std/include/range_algorithm_support.hpp | 223 ++++++++++++++++++ tests/std/test.lst | 1 + .../env.lst | 4 + .../test.cpp | 120 ++++++++++ 4 files changed, 348 insertions(+) create mode 100644 tests/std/tests/LWG4105_ranges_ends_with_and_integer_class/env.lst create mode 100644 tests/std/tests/LWG4105_ranges_ends_with_and_integer_class/test.cpp diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index b71b654f066..eb8e8247a09 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -935,6 +936,228 @@ namespace test { static_assert(false); } }; + + template + [[nodiscard]] constexpr auto to_unsigned(I n) noexcept { + if constexpr (std::signed_integral) { + return static_cast>(n); + } else { + return static_cast(n); + } + } + + template + struct redifference_iterator_category_base {}; + + template + requires std::signed_integral && requires { typename std::iterator_traits::iterator_category; } + struct redifference_iterator_category_base { + using iterator_category = std::iterator_traits::iterator_category; + using iterator_concept = decltype([] { + if constexpr (std::contiguous_iterator) { + return std::contiguous_iterator_tag{}; + } else if constexpr (std::random_access_iterator) { + return std::random_access_iterator_tag{}; + } else if constexpr (std::bidirectional_iterator) { + return std::bidirectional_iterator_tag{}; + } else if constexpr (std::forward_iterator) { + return std::forward_iterator_tag{}; + } else { + return std::input_iterator_tag{}; + } + }()); + }; + + template + class redifference_iterator : public redifference_iterator_category_base { + public: + using value_type = std::iter_value_t; + using difference_type = Diff; + + redifference_iterator() = default; + constexpr explicit redifference_iterator(It it) : i_{std::move(it)} {} + + [[nodiscard]] constexpr decltype(auto) operator*() const { + return *i_; + } + + constexpr decltype(auto) operator->() const + requires std::contiguous_iterator || (requires(const It& i) { i.operator->(); }) + { + if constexpr (std::contiguous_iterator) { + return std::to_address(i_); + } else { + return i_.operator->(); + } + } + + constexpr redifference_iterator& operator++() { + ++i_; + return *this; + } + + constexpr decltype(auto) operator++(int) { + if constexpr (std::is_same_v) { + return redifference_iterator{i_++}; + } else { + return i_++; + } + } + + constexpr redifference_iterator& operator--() + requires std::bidirectional_iterator + { + --i_; + return *this; + } + + constexpr redifference_iterator operator--(int) + requires std::bidirectional_iterator + { + return redifference_iterator{--i_}; + } + + constexpr redifference_iterator& operator+=(std::same_as auto n) + requires std::random_access_iterator + { + i_ += static_cast>(n); + return *this; + } + + constexpr redifference_iterator& operator-=(std::same_as auto n) + requires std::random_access_iterator + { + i_ -= static_cast>(n); + return *this; + } + + [[nodiscard]] constexpr decltype(auto) operator[](std::same_as auto n) const + requires std::random_access_iterator + { + return i_[static_cast>(n)]; + } + + [[nodiscard]] friend constexpr bool operator==(const redifference_iterator& i, const redifference_iterator& j) { + return i.i_ == j.i_; + } + + [[nodiscard]] friend constexpr redifference_iterator operator+( + const redifference_iterator& it, std::same_as auto n) + requires std::random_access_iterator + { + return redifference_iterator{it.i_ + static_cast>(n)}; + } + + [[nodiscard]] friend constexpr redifference_iterator operator+( + std::same_as auto n, const redifference_iterator& it) + requires std::random_access_iterator + { + return redifference_iterator{it.i_ + static_cast>(n)}; + } + + [[nodiscard]] friend constexpr redifference_iterator operator-( + const redifference_iterator& it, std::same_as auto n) + requires std::random_access_iterator + { + return redifference_iterator{it.i_ - static_cast>(n)}; + } + + [[nodiscard]] friend constexpr difference_type operator-( + const redifference_iterator& i, const redifference_iterator& j) + requires std::random_access_iterator + { + return static_cast(i.i_ - j.i_); + } + + [[nodiscard]] friend constexpr auto operator<=>(const redifference_iterator& i, const redifference_iterator& j) + requires std::random_access_iterator + { + if constexpr (std::three_way_comparable) { + return i.i_ <=> j.i_; + } else { + if (i.i_ < j.i_) { + return std::weak_ordering::less; + } else if (j.i_ < i.i_) { + return std::weak_ordering::greater; + } else { + return std::weak_ordering::equivalent; + } + } + } + + [[nodiscard]] friend constexpr bool operator<(const redifference_iterator& i, const redifference_iterator& j) + requires std::random_access_iterator + { + return i.i_ < j.i_; + } + + [[nodiscard]] friend constexpr bool operator>(const redifference_iterator& i, const redifference_iterator& j) + requires std::random_access_iterator + { + return j.i_ < i.i_; + } + + [[nodiscard]] friend constexpr bool operator<=(const redifference_iterator& i, const redifference_iterator& j) + requires std::random_access_iterator + { + return !(j.i_ < i.i_); + } + + [[nodiscard]] friend constexpr bool operator>=(const redifference_iterator& i, const redifference_iterator& j) + requires std::random_access_iterator + { + return !(i.i_ < j.i_); + } + + [[nodiscard]] constexpr const It& base() const noexcept { + return i_; + } + + private: + It i_; + }; + + template + struct redifference_sentinel { + S se_; + + template + requires std::sentinel_for + [[nodiscard]] friend constexpr bool operator==( + const redifference_iterator& i, const redifference_sentinel& s) { + return i.base() == s.se_; + } + + template + requires std::sized_sentinel_for + [[nodiscard]] friend constexpr Diff operator-( + const redifference_iterator& i, const redifference_sentinel& s) { + return static_cast(i.base() - s.se_); + } + template + requires std::sized_sentinel_for + [[nodiscard]] friend constexpr Diff operator-( + const redifference_sentinel& s, const redifference_iterator& i) { + return static_cast(s.se_ - i.base()); + } + }; + + template + [[nodiscard]] constexpr auto make_redifference_subrange(Rng&& r) { + constexpr bool is_sized = + ranges::sized_range || std::sized_sentinel_for, ranges::iterator_t>; + using rediff_iter = redifference_iterator>; + using rediff_sent = redifference_sentinel>; + + if constexpr (is_sized) { + const auto sz = to_unsigned(static_cast(ranges::distance(r))); + return ranges::subrange{ + rediff_iter{r.begin()}, rediff_sent{r.end()}, sz}; + } else { + return ranges::subrange{ + rediff_iter{r.begin()}, rediff_sent{r.end()}}; + } + } } // namespace test template +#include +#include +#include +#include +#include + +#include + +using namespace std; + +template +concept testable_range = ranges::input_range && (ranges::forward_range || ranges::sized_range); + +template +concept testable_sentinel = + ranges::input_range + && (ranges::forward_range || sized_sentinel_for, ranges::iterator_t>); + +struct instantiator { + static constexpr pair haystack[] = {{0, 42}, {1, 42}, {2, 42}, {4, 42}}; + static constexpr pair short_haystack[] = {{4, 42}}; + static constexpr pair long_needle[] = {{13, 1}, {13, 2}, {13, 4}}; + static constexpr pair short_needle[] = {{13, 2}, {13, 4}}; + static constexpr pair wrong_needle[] = {{13, 2}, {13, 3}}; + + template + static constexpr void test_range_rediff() { + using ranges::ends_with, ranges::equal_to; + + { + In1 r1{haystack}; + In2 r2{long_needle}; + const same_as auto match = ends_with(test::make_redifference_subrange(r1), + test::make_redifference_subrange(r2), equal_to{}, get_first, get_second); + assert(match); + } + { + In1 r1{haystack}; + In2 r2{short_needle}; + const same_as auto match = ends_with(test::make_redifference_subrange(r1), + test::make_redifference_subrange(r2), equal_to{}, get_first, get_second); + assert(match); + } + { + In1 r1{haystack}; + In2 r2{wrong_needle}; + const same_as auto match = ends_with(test::make_redifference_subrange(r1), + test::make_redifference_subrange(r2), equal_to{}, get_first, get_second); + assert(!match); + } + { + In1 r1{short_haystack}; + In2 r2{short_needle}; + const same_as auto match = ends_with(test::make_redifference_subrange(r1), + test::make_redifference_subrange(r2), equal_to{}, get_first, get_second); + assert(!match); + } + { + In1 r1{haystack}; + In2 r2{span, 0>{}}; + const same_as auto match = ends_with(test::make_redifference_subrange(r1), + test::make_redifference_subrange(r2), equal_to{}, get_first, get_second); + assert(match); + } + } + + template + static void call() { + if constexpr (testable_range && testable_range) { + using int_class = ranges::range_difference_t>; + + test_range_rediff(); + static_assert((test_range_rediff(), true)); + + test_range_rediff(); + static_assert((test_range_rediff(), true)); + } + } +}; + +#ifdef TEST_EVERYTHING +int main() { +#if !defined(_PREFAST_) && !defined(__EDG__) // TRANSITION, GH-1030 and GH-3567 + test_in_in, const pair>(); +#endif // ^^^ no workaround ^^^ +} +#else // ^^^ test all permutations of range properties / test only interesting permutations vvv +template +void run_tests_inner() { + instantiator::call, test::Sized::yes>>(); + instantiator::call, test::Sized::no>>(); + instantiator::call, test::Sized::yes>>(); + instantiator::call, test::Sized::no>>(); + instantiator::call, test::Sized::yes>>(); + instantiator::call, test::Sized::no>>(); + instantiator::call, test::Sized::yes>>(); + instantiator::call, test::Sized::no>>(); + instantiator::call, test::Sized::yes>>(); +} + +void run_tests() { + run_tests_inner, test::Sized::yes>>(); + run_tests_inner, test::Sized::no>>(); + run_tests_inner, test::Sized::yes>>(); + run_tests_inner, test::Sized::no>>(); + run_tests_inner, test::Sized::yes>>(); + run_tests_inner, test::Sized::no>>(); + run_tests_inner, test::Sized::yes>>(); + run_tests_inner, test::Sized::no>>(); + run_tests_inner, test::Sized::yes>>(); +} + +int main() { + run_tests(); +} +#endif // TEST_EVERYTHING From d5777f4fef078ba53211fa28382c588381d38eac Mon Sep 17 00:00:00 2001 From: ofAlpaca Date: Mon, 26 Aug 2024 02:15:25 +0800 Subject: [PATCH 07/42] Avoid truncation warnings for contiguous iterators with unusual difference types (#4898) Co-authored-by: Stephan T. Lavavej --- stl/inc/xutility | 4 +-- tests/std/test.lst | 1 + .../env.lst | 4 +++ .../test.compile.pass.cpp | 36 +++++++++++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 tests/std/tests/GH_003663_cast_contiguous_iterator_difference_type/env.lst create mode 100644 tests/std/tests/GH_003663_cast_contiguous_iterator_difference_type/test.compile.pass.cpp diff --git a/stl/inc/xutility b/stl/inc/xutility index 9097c517735..e223096dee4 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4659,7 +4659,7 @@ _OutCtgIt _Copy_memmove(_CtgIt _First, _CtgIt _Last, _OutCtgIt _Dest) { if constexpr (is_pointer_v<_OutCtgIt>) { return reinterpret_cast<_OutCtgIt>(_Dest_ch + _Count); } else { - return _Dest + (_LastPtr - _FirstPtr); + return _Dest + static_cast<_Iter_diff_t<_OutCtgIt>>(_LastPtr - _FirstPtr); } } @@ -4984,7 +4984,7 @@ _CtgIt2 _Copy_backward_memmove(_CtgIt1 _First, _CtgIt1 _Last, _CtgIt2 _Dest) { if constexpr (is_pointer_v<_CtgIt2>) { return static_cast<_CtgIt2>(_Result); } else { - return _Dest - (_LastPtr - _FirstPtr); + return _Dest - static_cast<_Iter_diff_t<_CtgIt2>>(_LastPtr - _FirstPtr); } } diff --git a/tests/std/test.lst b/tests/std/test.lst index 167b1f22a81..41ecb21be85 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -230,6 +230,7 @@ tests\GH_003119_error_category_ctor tests\GH_003246_cmath_narrowing tests\GH_003570_allocate_at_least tests\GH_003617_vectorized_meow_element +tests\GH_003663_cast_contiguous_iterator_difference_type 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 diff --git a/tests/std/tests/GH_003663_cast_contiguous_iterator_difference_type/env.lst b/tests/std/tests/GH_003663_cast_contiguous_iterator_difference_type/env.lst new file mode 100644 index 00000000000..351a8293d9d --- /dev/null +++ b/tests/std/tests/GH_003663_cast_contiguous_iterator_difference_type/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_20_matrix.lst diff --git a/tests/std/tests/GH_003663_cast_contiguous_iterator_difference_type/test.compile.pass.cpp b/tests/std/tests/GH_003663_cast_contiguous_iterator_difference_type/test.compile.pass.cpp new file mode 100644 index 00000000000..bc6547f0fe9 --- /dev/null +++ b/tests/std/tests/GH_003663_cast_contiguous_iterator_difference_type/test.compile.pass.cpp @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +class ContiguousIterator { +public: + using value_type = int; + using difference_type = int; + using element_type = int; + using iterator_category = std::contiguous_iterator_tag; + int* operator->() const; + int& operator*() const; + int& operator[](int) const; + ContiguousIterator& operator++(); + ContiguousIterator operator++(int); + ContiguousIterator& operator--(); + ContiguousIterator operator--(int); + ContiguousIterator& operator+=(int); + ContiguousIterator& operator-=(int); + friend auto operator<=>(ContiguousIterator, ContiguousIterator) = default; + friend int operator-(ContiguousIterator, ContiguousIterator); + friend ContiguousIterator operator+(ContiguousIterator, int); + friend ContiguousIterator operator-(ContiguousIterator, int); + friend ContiguousIterator operator+(int, ContiguousIterator); +}; + +static_assert(std::contiguous_iterator); + +// GH-3663 /: contiguous iterators with non-ptrdiff_t difference types +void test() { + int* p = nullptr; + std::copy(p, p, ContiguousIterator{}); + std::sort(ContiguousIterator{}, ContiguousIterator{}); +} From 77826845765c9593c9f9a502e04e04533710af5f Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Sun, 25 Aug 2024 11:27:23 -0700 Subject: [PATCH 08/42] Casey's accumulated miscellaneous changes (#4900) --- stl/inc/__msvc_iter_core.hpp | 5 ++++ stl/inc/forward_list | 4 +-- stl/inc/list | 4 +-- stl/inc/ranges | 32 ++++++++++------------ stl/inc/span | 6 ++++ stl/inc/utility | 20 ++++++++------ tests/std/tests/P0323R12_expected/test.cpp | 4 +-- 7 files changed, 42 insertions(+), 33 deletions(-) diff --git a/stl/inc/__msvc_iter_core.hpp b/stl/inc/__msvc_iter_core.hpp index 6107a8700aa..cc52fada0df 100644 --- a/stl/inc/__msvc_iter_core.hpp +++ b/stl/inc/__msvc_iter_core.hpp @@ -456,6 +456,11 @@ _EXPORT_STD using ranges::get; template constexpr bool _Is_subrange_v> = true; +#if _HAS_CXX23 +template +constexpr bool _Tuple_like_impl> = true; +#endif // _HAS_CXX23 + template struct tuple_size> : integral_constant {}; diff --git a/stl/inc/forward_list b/stl/inc/forward_list index afcdbf99254..ead270e4c99 100644 --- a/stl/inc/forward_list +++ b/stl/inc/forward_list @@ -1209,7 +1209,7 @@ public: }; auto remove(const _Ty& _Val) { // erase each element matching _Val - return remove_if([&](const _Ty& _Other) { return _Other == _Val; }); + return remove_if([&](const _Ty& _Other) -> bool { return _Other == _Val; }); } template @@ -1614,7 +1614,7 @@ _NODISCARD bool operator>=(const forward_list<_Ty, _Alloc>& _Left, const forward #if _HAS_CXX20 _EXPORT_STD template forward_list<_Ty, _Alloc>::size_type erase(forward_list<_Ty, _Alloc>& _Cont, const _Uty& _Val) { - return _Cont.remove_if([&](_Ty& _Elem) { return _Elem == _Val; }); + return _Cont.remove_if([&](_Ty& _Elem) -> bool { return _Elem == _Val; }); } _EXPORT_STD template diff --git a/stl/inc/list b/stl/inc/list index 84160362f46..3d427f80e6e 100644 --- a/stl/inc/list +++ b/stl/inc/list @@ -1663,7 +1663,7 @@ public: }; auto remove(const _Ty& _Val) { // erase each element matching _Val - return remove_if([&](const _Ty& _Other) { return _Other == _Val; }); + return remove_if([&](const _Ty& _Other) -> bool { return _Other == _Val; }); } template @@ -1916,7 +1916,7 @@ _NODISCARD bool operator>=(const list<_Ty, _Alloc>& _Left, const list<_Ty, _Allo #if _HAS_CXX20 _EXPORT_STD template list<_Ty, _Alloc>::size_type erase(list<_Ty, _Alloc>& _Cont, const _Uty& _Val) { - return _Cont.remove_if([&](_Ty& _Elem) { return _Elem == _Val; }); + return _Cont.remove_if([&](_Ty& _Elem) -> bool { return _Elem == _Val; }); } _EXPORT_STD template diff --git a/stl/inc/ranges b/stl/inc/ranges index db45abf8e13..62b8d6a1243 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -7134,7 +7134,7 @@ namespace ranges { const auto _Evaluate_equality_closure = [&_Lhs_tuple, &_Rhs_tuple](index_sequence<_Indices...>) noexcept( (noexcept(_STD declval() == _STD declval())&&...)) { - return ((_STD get<_Indices>(_Lhs_tuple) == _STD get<_Indices>(_Rhs_tuple)) || ...); + return ((_STD get<_Indices>(_Lhs_tuple) == _STD get<_Indices>(_Rhs_tuple)) || ... || false); }; return _Evaluate_equality_closure(index_sequence_for<_LHSTupleTypes...>{}); @@ -7455,6 +7455,11 @@ namespace ranges { } } + static constexpr auto _Size_closure = [](auto... _Sizes) _STATIC_CALL_OPERATOR noexcept { + using _Common_unsigned_type = _Make_unsigned_like_t>; + return (_RANGES min)({static_cast<_Common_unsigned_type>(_Sizes)...}); + }; + public: zip_view() noexcept((is_nothrow_default_constructible_v<_ViewTypes> && ...)) = default; @@ -7501,25 +7506,17 @@ namespace ranges { } _NODISCARD constexpr auto size() noexcept( - noexcept(_STD apply(_Size_closure(), _Tuple_transform(_RANGES size, _Views)))) // strengthened + noexcept(_STD apply(_Size_closure, _Tuple_transform(_RANGES size, _Views)))) // strengthened requires (sized_range<_ViewTypes> && ...) { - return _STD apply(_Size_closure(), _Tuple_transform(_RANGES size, _Views)); + return _STD apply(_Size_closure, _Tuple_transform(_RANGES size, _Views)); } _NODISCARD constexpr auto size() const - noexcept(noexcept(_STD apply(_Size_closure(), _Tuple_transform(_RANGES size, _Views)))) // strengthened + noexcept(noexcept(_STD apply(_Size_closure, _Tuple_transform(_RANGES size, _Views)))) // strengthened requires (sized_range && ...) { - return _STD apply(_Size_closure(), _Tuple_transform(_RANGES size, _Views)); - } - - private: - _NODISCARD static constexpr auto _Size_closure() noexcept { - return [](auto... _Sizes) _STATIC_CALL_OPERATOR noexcept { - using _Common_unsigned_type = _Make_unsigned_like_t>; - return (_RANGES min)({static_cast<_Common_unsigned_type>(_Sizes)...}); - }; + return _STD apply(_Size_closure, _Tuple_transform(_RANGES size, _Views)); } }; @@ -9094,9 +9091,8 @@ namespace ranges { requires (indirectly_swappable>> && ... && indirectly_swappable>>) { - return [&](index_sequence<_Indices...>) { - return (_RANGES iter_swap(_STD get<_Indices>(_Left._Current), _STD get<_Indices>(_Right._Current)), - ...); + [&](index_sequence<_Indices...>) { + (_RANGES iter_swap(_STD get<_Indices>(_Left._Current), _STD get<_Indices>(_Right._Current)), ...); }(make_index_sequence<1 + sizeof...(_Rest)>{}); } }; @@ -9144,7 +9140,7 @@ namespace ranges { requires ((!_Simple_view<_First> || ... || !_Simple_view<_Rest>) && _Cartesian_product_is_common<_First>) { const bool _Is_empty = [&](index_sequence<_Indices...>) { - return (_RANGES empty(_STD get<_Indices + 1>(_Bases)) || ...); + return (_RANGES empty(_STD get<_Indices + 1>(_Bases)) || ... || false); }(make_index_sequence{}); const auto _Make_iter_tuple = [&](index_sequence<_Indices...>) { @@ -9157,7 +9153,7 @@ namespace ranges { requires _Cartesian_product_is_common { const bool _Is_empty = [&](index_sequence<_Indices...>) { - return (_RANGES empty(_STD get<_Indices + 1>(_Bases)) || ...); + return (_RANGES empty(_STD get<_Indices + 1>(_Bases)) || ... || false); }(make_index_sequence{}); const auto _Make_iter_tuple = [&](index_sequence<_Indices...>) { diff --git a/stl/inc/span b/stl/inc/span index 018bc98cc98..d30d805d105 100644 --- a/stl/inc/span +++ b/stl/inc/span @@ -235,6 +235,12 @@ constexpr bool _Is_span_v = false; template constexpr bool _Is_span_v> = true; +template +constexpr bool _Is_std_array_v = false; + +template +constexpr bool _Is_std_array_v> = true; + // clang-format off template concept _Span_compatible_iterator = contiguous_iterator<_It> diff --git a/stl/inc/utility b/stl/inc/utility index f86e318e398..2281bf7c019 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -200,19 +200,21 @@ _NODISCARD constexpr const _Ty&& get(const array<_Ty, _Size>&& _Arr) noexcept; template concept _Different_from = !same_as, remove_cvref_t<_Ty2>>; -template -constexpr bool _Is_std_array_v = false; - -template -constexpr bool _Is_std_array_v> = true; - template constexpr bool _Is_subrange_v = false; #if _HAS_CXX23 -template -constexpr bool _Tuple_like_impl = - _Is_specialization_v<_Ty, tuple> || _Is_specialization_v<_Ty, pair> || _Is_std_array_v<_Ty> || _Is_subrange_v<_Ty>; +template +constexpr bool _Tuple_like_impl = false; + +template +constexpr bool _Tuple_like_impl> = true; + +template +constexpr bool _Tuple_like_impl> = true; + +template +constexpr bool _Tuple_like_impl> = true; template concept _Tuple_like = _Tuple_like_impl>; diff --git a/tests/std/tests/P0323R12_expected/test.cpp b/tests/std/tests/P0323R12_expected/test.cpp index 1c97c0092c3..82a8d09d0ed 100644 --- a/tests/std/tests/P0323R12_expected/test.cpp +++ b/tests/std/tests/P0323R12_expected/test.cpp @@ -2232,8 +2232,8 @@ void test_reinit_regression() { } } -// Defend against regression of llvm-project#59854, in which clang is confused -// by the explicit `noexcept` on `expected`'s destructors. +// Defend against regression of LLVM-59854, in which clang is confused by the +// explicit `noexcept` on `expected`'s destructors. struct Data { vector vec_; constexpr Data(initializer_list il) : vec_(il) {} From c2ab0400bb3f1f367afcfbb5722193fe6b1e9bd0 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 26 Aug 2024 02:35:11 +0800 Subject: [PATCH 09/42] Speculatively implement LWG-4139 [time.zone.leap] recursive constraint in `<=>` (#4902) --- stl/inc/chrono | 116 ++++++++++-------- .../test.cpp | 59 +++++++++ 2 files changed, 122 insertions(+), 53 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index 4a8e089c91a..67593076fb1 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -1944,65 +1944,75 @@ namespace chrono { return _Elapsed_offset; } - private: - sys_seconds _Date; - bool _Is_positive; - seconds _Elapsed_offset; - }; + _NODISCARD friend constexpr bool operator==(const leap_second& _Left, const leap_second& _Right) noexcept { + return _Left.date() == _Right.date(); + } + template + _NODISCARD friend constexpr bool operator==( + const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { + return _Left.date() == _Right; + } - _EXPORT_STD _NODISCARD constexpr bool operator==(const leap_second& _Left, const leap_second& _Right) noexcept { - return _Left.date() == _Right.date(); - } - _EXPORT_STD template - _NODISCARD constexpr bool operator==(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { - return _Left.date() == _Right; - } + template + _NODISCARD friend constexpr bool operator<( + const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { + return _Left.date() < _Right; + } + template + _NODISCARD friend constexpr bool operator<( + const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept { + return _Left < _Right.date(); + } - _EXPORT_STD template - _NODISCARD constexpr bool operator<(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { - return _Left.date() < _Right; - } - _EXPORT_STD template - _NODISCARD constexpr bool operator<(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept { - return _Left < _Right.date(); - } + template + _NODISCARD friend constexpr bool operator>( + const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { + return _Right < _Left.date(); + } + template + _NODISCARD friend constexpr bool operator>( + const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept { + return _Right.date() < _Left; + } - _EXPORT_STD template - _NODISCARD constexpr bool operator>(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { - return _Right < _Left.date(); - } - _EXPORT_STD template - _NODISCARD constexpr bool operator>(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept { - return _Right.date() < _Left; - } + template + _NODISCARD friend constexpr bool operator<=( + const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { + return !(_Right < _Left.date()); + } + template + _NODISCARD friend constexpr bool operator<=( + const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept { + return !(_Right.date() < _Left); + } - _EXPORT_STD template - _NODISCARD constexpr bool operator<=(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { - return !(_Right < _Left.date()); - } - _EXPORT_STD template - _NODISCARD constexpr bool operator<=(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept { - return !(_Right.date() < _Left); - } + template + _NODISCARD friend constexpr bool operator>=( + const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { + return !(_Left.date() < _Right); + } + template + _NODISCARD friend constexpr bool operator>=( + const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept { + return !(_Left < _Right.date()); + } - _EXPORT_STD template - _NODISCARD constexpr bool operator>=(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { - return !(_Left.date() < _Right); - } - _EXPORT_STD template - _NODISCARD constexpr bool operator>=(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept { - return !(_Left < _Right.date()); - } + template + requires three_way_comparable_with> + _NODISCARD friend constexpr auto operator<=>( + const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { + return _Left.date() <=> _Right; + } + _NODISCARD friend constexpr strong_ordering operator<=>( + const leap_second& _Left, const leap_second& _Right) noexcept { + return _Left.date() <=> _Right.date(); + } - _EXPORT_STD template - requires three_way_comparable_with> - _NODISCARD constexpr auto operator<=>(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { - return _Left.date() <=> _Right; - } - _EXPORT_STD _NODISCARD constexpr strong_ordering operator<=>( - const leap_second& _Left, const leap_second& _Right) noexcept { - return _Left.date() <=> _Right.date(); - } + private: + sys_seconds _Date; + bool _Is_positive; + seconds _Elapsed_offset; + }; // [time.zone.link] diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp index a0b24b0b320..eb4812739ba 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp @@ -7,10 +7,12 @@ #include #include #include +#include #include #include #include +#include #include using namespace std; @@ -475,6 +477,63 @@ void test() { } } +// LWG-4139 "[time.zone.leap] recursive constraint in <=>" +namespace lwg_4139 { + struct conv_to_leap_second : local_t { + operator leap_second() const noexcept; + }; + + static_assert(equality_comparable == is_permissive); + static_assert(equality_comparable_with == is_permissive); + static_assert(totally_ordered == is_permissive); + static_assert(totally_ordered_with == is_permissive); + static_assert(three_way_comparable == is_permissive); + static_assert(three_way_comparable_with == is_permissive); + + using ref_leap_second = reference_wrapper; + + static_assert(equality_comparable); + static_assert(equality_comparable_with); + static_assert(totally_ordered); + static_assert(totally_ordered_with); + static_assert(three_way_comparable); + static_assert(three_way_comparable_with); + + template + concept can_equality_compare_with = requires(const remove_reference_t& t, const remove_reference_t& u) { + t == u; + t != u; + u == t; + u != t; + }; + + template + concept can_relation_compare_with = requires(const remove_reference_t& t, const remove_reference_t& u) { + t < u; + t > u; + t <= u; + t >= u; + u < t; + u > t; + u <= t; + u >= t; + }; + + template + concept can_three_way_compare_with = requires(const remove_reference_t& t, const remove_reference_t& u) { + t <=> u; + u <=> t; + }; + + static_assert(!can_equality_compare_with); + static_assert(!can_relation_compare_with); + static_assert(!can_three_way_compare_with); + + static_assert(can_equality_compare_with); + static_assert(can_relation_compare_with); + static_assert(can_three_way_compare_with); +} // namespace lwg_4139 + int main() { run_tz_test([] { test(); }); } From 75d3e6caa063a9b805f3d9278735d55b8bf000dc Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 26 Aug 2024 02:54:50 +0800 Subject: [PATCH 10/42] ``: Workaround for LLVM-59854 in the case of destructor of `variant` (#4903) Co-authored-by: Casey Carter --- stl/inc/variant | 6 +- tests/std/tests/P0088R3_variant_msvc/test.cpp | 83 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/stl/inc/variant b/stl/inc/variant index 7ebf3b6cf60..f27bddbc911 100644 --- a/stl/inc/variant +++ b/stl/inc/variant @@ -378,7 +378,11 @@ public: _Variant_storage<_Rest...> _Tail; }; - _CONSTEXPR20 ~_Variant_storage_() noexcept { + _CONSTEXPR20 ~_Variant_storage_() +#ifndef __clang__ // TRANSITION, LLVM-59854 + noexcept +#endif // ^^^ no workaround ^^^ + { // explicitly non-trivial destructor (which would otherwise be defined as deleted // since the class has a variant member with a non-trivial destructor) } diff --git a/tests/std/tests/P0088R3_variant_msvc/test.cpp b/tests/std/tests/P0088R3_variant_msvc/test.cpp index adcb2967aee..412d93d68e4 100644 --- a/tests/std/tests/P0088R3_variant_msvc/test.cpp +++ b/tests/std/tests/P0088R3_variant_msvc/test.cpp @@ -741,6 +741,89 @@ namespace msvc { } } // namespace gh2770 + namespace gh4901 { +#if _HAS_CXX20 +#define CONSTEXPR20 constexpr +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +#define CONSTEXPR20 inline +#endif // ^^^ !_HAS_CXX20 ^^^ + struct X { + CONSTEXPR20 ~X() {} + }; + + struct Y { + X _; + }; + + struct ZA { + std::variant z; + }; + + struct ZB { + std::variant z; + }; + +#if _HAS_CXX20 + static_assert(ZA{0}.z.index() == 1); + static_assert(ZA{Y{}}.z.index() == 0); + static_assert(ZB{0}.z.index() == 0); + static_assert(ZB{Y{}}.z.index() == 1); +#endif // _HAS_CXX20 + + static_assert(std::is_nothrow_destructible_v); + static_assert(std::is_nothrow_destructible_v); + static_assert(std::is_nothrow_destructible_v>); + static_assert(std::is_nothrow_destructible_v>); + static_assert(std::is_nothrow_destructible_v); + static_assert(std::is_nothrow_destructible_v); + + // Verify that variant::~variant is noexcept even when an alternative has a potentially-throwing destructor, + // per N4988 [res.on.exception.handling]/3. + struct X2 { + CONSTEXPR20 ~X2() noexcept(false) {} + }; + + struct Y2 { + X2 _; + }; + + struct ZA2 { + std::variant z; + }; + + struct ZB2 { + std::variant z; + }; + +#if _HAS_CXX20 + static_assert(ZA2{0}.z.index() == 1); + static_assert(ZA2{Y2{}}.z.index() == 0); + static_assert(ZB2{0}.z.index() == 0); + static_assert(ZB2{Y2{}}.z.index() == 1); +#endif // _HAS_CXX20 + + static_assert(!std::is_nothrow_destructible_v); + static_assert(!std::is_nothrow_destructible_v); + static_assert(std::is_nothrow_destructible_v>); + static_assert(std::is_nothrow_destructible_v>); + static_assert(std::is_nothrow_destructible_v); + static_assert(std::is_nothrow_destructible_v); + + struct ZC { + std::variant z; + }; + +#if _HAS_CXX20 + static_assert(ZC{Y{}}.z.index() == 0); + static_assert(ZC{0}.z.index() == 1); + static_assert(ZC{Y2{}}.z.index() == 2); +#endif // _HAS_CXX20 + + static_assert(std::is_nothrow_destructible_v>); + static_assert(std::is_nothrow_destructible_v); +#undef CONSTEXPR20 + } // namespace gh4901 + namespace assign_cv { template struct TypeIdentityImpl { From d1f63f34fc78f19544202f85cac3dde49e3a5537 Mon Sep 17 00:00:00 2001 From: YexuanXiao Date: Mon, 26 Aug 2024 03:02:25 +0800 Subject: [PATCH 11/42] Optimize equality comparison of two empty `string_view`s (#4904) Co-authored-by: Casey Carter Co-authored-by: Stephan T. Lavavej --- benchmarks/CMakeLists.txt | 1 + benchmarks/src/sv_equal.cpp | 75 ++++++++++++++++++++++++++++++++++ stl/inc/__msvc_string_view.hpp | 10 ++++- 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 benchmarks/src/sv_equal.cpp diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 6b71cb76f25..7c98173e061 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -121,6 +121,7 @@ add_benchmark(random_integer_generation src/random_integer_generation.cpp) add_benchmark(replace src/replace.cpp) add_benchmark(search src/search.cpp) add_benchmark(std_copy src/std_copy.cpp) +add_benchmark(sv_equal src/sv_equal.cpp) add_benchmark(swap_ranges src/swap_ranges.cpp) add_benchmark(vector_bool_copy src/std/containers/sequences/vector.bool/copy/test.cpp) diff --git a/benchmarks/src/sv_equal.cpp b/benchmarks/src/sv_equal.cpp new file mode 100644 index 00000000000..ee47ab63c87 --- /dev/null +++ b/benchmarks/src/sv_equal.cpp @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +using namespace std::string_view_literals; + +constexpr auto haystack = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mollis imperdiet massa, at dapibus elit " + "interdumac. In eget sollicitudin mi. Nam at tellus at sapien tincidunt sollicitudin vel non eros. Pellentesque " + "nunc nunc,ullamcorper eu accumsan at, pulvinar non turpis. Quisque vel mauris pulvinar, pretium purus vel, " + "ultricies erat.Curabitur a magna in ligula tristique ornare. Quisque commodo, massa viverra laoreet luctus, sem " + "nisi aliquamvelit, fermentum pulvinar velit leo eget justo. Suspendisse vel erat efficitur, pulvinar eros " + "volutpat, vulputateex. Phasellus non purus vel velit tristique tristique id at ligula. Quisque mollis sodales " + "magna. Mauris et quameu quam viverra tempus. Nullam tempus maximus porta. Nunc mattis eleifend fermentum. Nullam " + "aliquam liberoaccumsan velit elementum, eu laoreet metus convallis. Donec pellentesque lacus ut iaculis iaculis. " + "Curabitur orcielit, bibendum sit amet feugiat at, iaculis sit amet massa. Maecenas imperdiet lacus at vehicula " + "iaculis. Donecvolutpat nunc sit amet accumsan tempor. Quisque pretium vestibulum ultricies. Suspendisse potenti. " + "Aenean at diamiaculis, condimentum felis venenatis, condimentum erat. Nam quis elit dui. Duis quis odio vitae " + "metus hendreritrhoncus ut et magna. Cras ac augue quis nibh pharetra sagittis. Donec ullamcorper vel eros semper " + "pretium. Proinvel sollicitudin eros. Nulla sollicitudin mattis turpis id suscipit. Aliquam sed risus velit. " + "Aliquam iaculis necnibh ac egestas. Duis finibus semper est sed consequat. Sed in sapien quis nibh dignissim " + "mattis. Vestibulum necmetus sodales, euismod mauris ac, sollicitudin libero. Maecenas non arcu ac velit " + "ullamcorper fringilla et quisnulla. Curabitur posuere leo eget ipsum tincidunt dignissim. Cras ultricies suscipit " + "neque, quis suscipit tortorvenenatis non. Cras nisl mi, bibendum in vulputate quis, vestibulum ornare enim. Nunc " + "hendrerit placerat dui,aliquam mollis sem convallis et. Integer vitae urna diam. Phasellus et imperdiet est. " + "Maecenas auctor facilisisnibh non commodo. Suspendisse iaculis quam "sv; + +constexpr std::size_t Count = 8u; + +template +constexpr std::array make_svs() { + std::array result{}; + + if constexpr (Length != 0) { + using namespace std::views; + + std::ranges::copy( + haystack | chunk(Length) | transform([](auto&& t) { return std::string_view(t); }) | take(Count), + result.begin()); + } + + return result; +} + +template +void sv_equal(benchmark::State& state) { + constexpr auto arr = make_svs(); + benchmark::DoNotOptimize(arr); + + for (auto _ : state) { + for (auto& i : arr) { + benchmark::DoNotOptimize(i); + auto res = (i == arr[0]); + benchmark::DoNotOptimize(res); + } + } +} + +BENCHMARK(sv_equal<0>); +BENCHMARK(sv_equal<8>); +BENCHMARK(sv_equal<16>); +BENCHMARK(sv_equal<32>); +BENCHMARK(sv_equal<64>); +BENCHMARK(sv_equal<128>); +BENCHMARK(sv_equal<256>); + +static_assert(haystack.size() >= Count * 256, "haystack is too small"); + +BENCHMARK_MAIN(); diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index acc6ac364be..0ccf5a31c30 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -528,7 +528,15 @@ template constexpr bool _Traits_equal(_In_reads_(_Left_size) const _Traits_ptr_t<_Traits> _Left, const size_t _Left_size, _In_reads_(_Right_size) const _Traits_ptr_t<_Traits> _Right, const size_t _Right_size) noexcept { // compare [_Left, _Left + _Left_size) to [_Right, _Right + _Right_size) for equality using _Traits - return _Left_size == _Right_size && _Traits::compare(_Left, _Right, _Left_size) == 0; + if (_Left_size != _Right_size) { + return false; + } + + if (_Left_size == 0u) { + return true; + } + + return _Traits::compare(_Left, _Right, _Left_size) == 0; } template From 5f119276ac7c6b8758ba1325ec6c909d75b555e6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 25 Aug 2024 12:06:35 -0700 Subject: [PATCH 12/42] Fix MSVC-only compiler options for the internal test harness (#4905) --- tests/std/run.pl | 2 +- tests/tr1/run.pl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/run.pl b/tests/std/run.pl index 004ae4ce689..6258d2ebcb0 100644 --- a/tests/std/run.pl +++ b/tests/std/run.pl @@ -34,7 +34,7 @@ # add additional compiler flags if the compiler is cl.exe. if (not $ENV{PM_COMPILER}) { - $ENV{CL} .= " " . $ENV{PM_CL_MSVC}; + $ENV{PM_CL} .= " " . $ENV{PM_CL_MSVC}; } my $RunPL = ""; diff --git a/tests/tr1/run.pl b/tests/tr1/run.pl index 004ae4ce689..6258d2ebcb0 100644 --- a/tests/tr1/run.pl +++ b/tests/tr1/run.pl @@ -34,7 +34,7 @@ # add additional compiler flags if the compiler is cl.exe. if (not $ENV{PM_COMPILER}) { - $ENV{CL} .= " " . $ENV{PM_CL_MSVC}; + $ENV{PM_CL} .= " " . $ENV{PM_CL_MSVC}; } my $RunPL = ""; From 138e1161c995209afb9644d87beb7f5e33747d38 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 25 Aug 2024 12:22:04 -0700 Subject: [PATCH 13/42] Standard Library Modules: Add compiler workarounds for `` (#4906) --- stl/inc/__msvc_int128.hpp | 8 ++++---- tests/std/include/test_header_units_and_modules.hpp | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index cef5bd87c0a..9a3f2e3c69b 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -707,9 +707,9 @@ struct _Unsigned128 : _Base128 { using _Signed_type = _Signed128; using _Unsigned_type = _Unsigned128; -#if !_HAS_CXX17 +#if !_HAS_CXX17 || (_HAS_CXX20 && !defined(__clang__) && !defined(__EDG__)) // TRANSITION, DevCom-10729775 constexpr _Unsigned128() noexcept : _Base128{} {} -#endif // !_HAS_CXX17 +#endif // ^^^ workaround for C++20 MSVC modules and header units; should be guarded for !_HAS_CXX17 only ^^^ using _Base128::_Base128; constexpr explicit _Unsigned128(const _Base128& _That) noexcept : _Base128{_That} {} @@ -1024,9 +1024,9 @@ struct _Signed128 : _Base128 { using _Signed_type = _Signed128; using _Unsigned_type = _Unsigned128; -#if !_HAS_CXX17 +#if !_HAS_CXX17 || (_HAS_CXX20 && !defined(__clang__) && !defined(__EDG__)) // TRANSITION, DevCom-10729775 constexpr _Signed128() noexcept : _Base128{} {} -#endif // !_HAS_CXX17 +#endif // ^^^ workaround for C++20 MSVC modules and header units; should be guarded for !_HAS_CXX17 only ^^^ using _Base128::_Base128; constexpr explicit _Signed128(const _Base128& _That) noexcept : _Base128{_That} {} diff --git a/tests/std/include/test_header_units_and_modules.hpp b/tests/std/include/test_header_units_and_modules.hpp index ceab5eb2d56..c37a5173030 100644 --- a/tests/std/include/test_header_units_and_modules.hpp +++ b/tests/std/include/test_header_units_and_modules.hpp @@ -593,6 +593,14 @@ void test_random() { minstd_rand0 lcg; lcg.discard(9999); assert(lcg() == 1043618065); // N4868 [rand.predef]/1 + +#ifndef _MSVC_INTERNAL_TESTING // TRANSITION, VSO-2226569 + // Test coverage for GH-4899 "Standard Library Modules: uniform_real_distribution emits + // error C2512: 'std::_Unsigned128': no appropriate default constructor available": + const double val = generate_canonical(lcg); + assert(val >= 0.0); + assert(val < 1.0); +#endif // ^^^ no workaround ^^^ } void test_ranges() { From d4b84bc4caca41726111c9f7b918b97d50326ed5 Mon Sep 17 00:00:00 2001 From: Spring Burst <16273755+Andor233@users.noreply.github.com> Date: Mon, 26 Aug 2024 03:33:07 +0800 Subject: [PATCH 14/42] ``: crash when formatting a floating-point value with #/L and a large precision (#4907) --- stl/inc/format | 2 +- .../test.cpp | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/stl/inc/format b/stl/inc/format index c2af86f05a3..e5ac72dcc0a 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -3095,7 +3095,7 @@ _NODISCARD _OutputIt _Fmt_write( switch (_Format) { case chars_format::hex: case chars_format::scientific: - if (_Extra_precision != 0) { + if (_Extra_precision != 0 && !_Specs._Alt && !_Specs._Localized) { // Trailing zeroes are in front of the exponent while (*--_Exponent_start != _Exponent) { } diff --git a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp index c6295a44c3e..0b0b569f1c4 100644 --- a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp @@ -1520,6 +1520,26 @@ void test_gh_4319() { assert(format(STR("{:}"), 12345678.0) == STR("12345678")); } +// GH-4320: : crash when formatting a floating-point value with #/L and a large precision +template +void test_gh_4320() { + assert( + format(STR("{:#.1075e}"), 1.0) + == STR( + "1." + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000e+00")); +} + void test() { test_simple_formatting(); test_simple_formatting(); @@ -1604,6 +1624,8 @@ void test() { test_gh_4319(); test_gh_4319(); + test_gh_4320(); + test_gh_4320(); } int main() { From 8af2cc499c94271c8d12baeb45e840f7160e082d Mon Sep 17 00:00:00 2001 From: Daniel Marshall Date: Sun, 25 Aug 2024 20:41:38 +0100 Subject: [PATCH 15/42] ``: rename `views::iota` and `views::repeat` parameters (#4908) --- stl/inc/ranges | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 62b8d6a1243..692a65504cf 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -1051,11 +1051,12 @@ namespace ranges { } template - _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Ty1&& _Val1, _Ty2&& _Val2) _CONST_CALL_OPERATOR - noexcept(noexcept(iota_view(static_cast<_Ty1&&>(_Val1), static_cast<_Ty2&&>(_Val2)))) - requires requires { iota_view(static_cast<_Ty1&&>(_Val1), static_cast<_Ty2&&>(_Val2)); } + _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()( + _Ty1&& _Start, _Ty2&& _Bound) _CONST_CALL_OPERATOR + noexcept(noexcept(iota_view(static_cast<_Ty1&&>(_Start), static_cast<_Ty2&&>(_Bound)))) + requires requires { iota_view(static_cast<_Ty1&&>(_Start), static_cast<_Ty2&&>(_Bound)); } { - return iota_view(static_cast<_Ty1&&>(_Val1), static_cast<_Ty2&&>(_Val2)); + return iota_view(static_cast<_Ty1&&>(_Start), static_cast<_Ty2&&>(_Bound)); } }; @@ -1306,11 +1307,12 @@ namespace ranges { } template - _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Ty1&& _Val1, _Ty2&& _Val2) _CONST_CALL_OPERATOR - noexcept(noexcept(repeat_view(_STD forward<_Ty1>(_Val1), _STD forward<_Ty2>(_Val2)))) - requires requires { repeat_view(_STD forward<_Ty1>(_Val1), _STD forward<_Ty2>(_Val2)); } + _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()( + _Ty1&& _Value, _Ty2&& _Count) _CONST_CALL_OPERATOR + noexcept(noexcept(repeat_view(_STD forward<_Ty1>(_Value), _STD forward<_Ty2>(_Count)))) + requires requires { repeat_view(_STD forward<_Ty1>(_Value), _STD forward<_Ty2>(_Count)); } { - return repeat_view(_STD forward<_Ty1>(_Val1), _STD forward<_Ty2>(_Val2)); + return repeat_view(_STD forward<_Ty1>(_Value), _STD forward<_Ty2>(_Count)); } }; From d9f6f3104e99a9b6b6a4082a2b1be189ea7976a0 Mon Sep 17 00:00:00 2001 From: Jonathan Emmett Date: Tue, 27 Aug 2024 15:35:45 -0300 Subject: [PATCH 16/42] Adjust tests relying on CWG1351 noexcept behavior (#4914) Update some noexcept tests in variant and invoke to remove old permissive behavior. This is guarded in a check for an as-yet unreleased MSVC compiler. --- tests/std/tests/P0088R3_variant/test.cpp | 16 ++++++++++++---- tests/std/tests/P2136R3_invoke_r/test.cpp | 7 ++++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/tests/std/tests/P0088R3_variant/test.cpp b/tests/std/tests/P0088R3_variant/test.cpp index 58a54cbdaad..403a873116d 100644 --- a/tests/std/tests/P0088R3_variant/test.cpp +++ b/tests/std/tests/P0088R3_variant/test.cpp @@ -285,7 +285,9 @@ void test_const_lvalue_get() { { using V = std::variant; constexpr V v(42); - static_assert(noexcept(std::get<0>(v)) == is_permissive); +#if defined(_MSVC_INTERNAL_TESTING) || defined(__clang__) || defined(__EDG__) // TRANSITION, vs17.12p3 + ASSERT_NOT_NOEXCEPT(std::get<0>(v)); +#endif // ^^^ no workaround ^^^ ASSERT_SAME_TYPE(decltype(std::get<0>(v)), const int &); static_assert(std::get<0>(v) == 42, ""); } @@ -299,7 +301,9 @@ void test_const_lvalue_get() { { using V = std::variant; constexpr V v(42l); - static_assert(noexcept(std::get<1>(v)) == is_permissive); +#if defined(_MSVC_INTERNAL_TESTING) || defined(__clang__) || defined(__EDG__) // TRANSITION, vs17.12p3 + ASSERT_NOT_NOEXCEPT(std::get<1>(v)); +#endif // ^^^ no workaround ^^^ ASSERT_SAME_TYPE(decltype(std::get<1>(v)), const long &); static_assert(std::get<1>(v) == 42, ""); } @@ -447,7 +451,9 @@ void test_const_lvalue_get() { { using V = std::variant; constexpr V v(42); - static_assert(noexcept(std::get(v)) == is_permissive); +#if defined(_MSVC_INTERNAL_TESTING) || defined(__clang__) || defined(__EDG__) // TRANSITION, vs17.12p3 + ASSERT_NOT_NOEXCEPT(std::get(v)); +#endif // ^^^ no workaround ^^^ ASSERT_SAME_TYPE(decltype(std::get(v)), const int &); static_assert(std::get(v) == 42, ""); } @@ -461,7 +467,9 @@ void test_const_lvalue_get() { { using V = std::variant; constexpr V v(42l); - static_assert(noexcept(std::get(v)) == is_permissive); +#if defined(_MSVC_INTERNAL_TESTING) || defined(__clang__) || defined(__EDG__) // TRANSITION, vs17.12p3 + ASSERT_NOT_NOEXCEPT(std::get(v)); +#endif // ^^^ no workaround ^^^ ASSERT_SAME_TYPE(decltype(std::get(v)), const long &); static_assert(std::get(v) == 42, ""); } diff --git a/tests/std/tests/P2136R3_invoke_r/test.cpp b/tests/std/tests/P2136R3_invoke_r/test.cpp index 06f36ce8ed9..c08da1afd35 100644 --- a/tests/std/tests/P2136R3_invoke_r/test.cpp +++ b/tests/std/tests/P2136R3_invoke_r/test.cpp @@ -50,9 +50,10 @@ constexpr bool test_invoke_r() { static_assert(is_same_v); static_assert(is_void_v(square, 1))>); - // TRANSITION, DevCom-1457457 - static_assert(noexcept(invoke_r(square, 3)) == is_permissive); - static_assert(noexcept(invoke(square, 3)) == is_permissive); +#if defined(_MSVC_INTERNAL_TESTING) || defined(__clang__) || defined(__EDG__) // TRANSITION, vs17.12p3 + static_assert(!noexcept(invoke_r(square, 3))); + static_assert(!noexcept(invoke(square, 3))); +#endif // ^^^ no workaround ^^^ constexpr bool has_noexcept_in_type = #ifdef __cpp_noexcept_function_type From 3e20579d1d97a782c394d3e9ea44f869704d7cb7 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 27 Aug 2024 21:19:18 -0700 Subject: [PATCH 17/42] Unskip tests that no longer have `ALLOW_RETRIES` (#4911) Co-authored-by: Stephan T. Lavavej --- tests/libcxx/expected_results.txt | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 6f0059892bd..ee6341e94cd 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -504,36 +504,6 @@ std/thread/futures/futures.async/async.pass.cpp SKIPPED std/thread/futures/futures.unique_future/wait_for.pass.cpp SKIPPED std/thread/thread.condition/thread.condition.condvarany/notify_one.pass.cpp SKIPPED std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex_try_to_lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_duration.pass.cpp SKIPPED -std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_time_point.pass.cpp SKIPPED -std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_try_to_lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex.pass.cpp SKIPPED -std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/try_lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/try_lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.shared_mutex.requirements/thread.shared_mutex.class/lock_shared.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.shared_mutex.requirements/thread.shared_mutex.class/lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.shared_mutex.requirements/thread.shared_mutex.class/try_lock_shared.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.shared_mutex.requirements/thread.shared_mutex.class/try_lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/lock_shared.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/try_lock_for.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/try_lock_shared_for.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/try_lock_shared_until.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/try_lock_shared.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/try_lock_until.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/try_lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.class/lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.class/try_lock_for.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.class/try_lock_until.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.class/try_lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/lock.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/try_lock_for.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/try_lock_until.pass.cpp SKIPPED -std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/try_lock.pass.cpp SKIPPED # Not analyzed, likely bogus tests. Appears to be timing assumptions. std/thread/futures/futures.shared_future/get.pass.cpp SKIPPED From 4811be844f66615443916d62e528e573e575b7a1 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 27 Aug 2024 21:22:57 -0700 Subject: [PATCH 18/42] Make the test suite more friendly to Clang 19 (#4912) Co-authored-by: Stephan T. Lavavej --- tests/libcxx/expected_results.txt | 1 + .../P2286R8_text_formatting_range_formatter/test.cpp | 8 ++++---- .../test.compile.pass.cpp | 4 ++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index ee6341e94cd..1b16cd15017 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -368,6 +368,7 @@ std/depr/depr.c.headers/tgmath_h.pass.cpp:2 FAIL # LLVM-95311 [clang] __has_unique_object_representations gives inconsistent answer based on instantiation order # A libc++ product code workaround (using `remove_all_extents_t`) and test coverage were added by LLVM-95314. +# Fixed by LLVM-95432 in Clang 19. std/utilities/meta/meta.unary/meta.unary.prop/has_unique_object_representations.compile.pass.cpp:2 FAIL diff --git a/tests/std/tests/P2286R8_text_formatting_range_formatter/test.cpp b/tests/std/tests/P2286R8_text_formatting_range_formatter/test.cpp index a0f9d987226..38652a1fa63 100644 --- a/tests/std/tests/P2286R8_text_formatting_range_formatter/test.cpp +++ b/tests/std/tests/P2286R8_text_formatting_range_formatter/test.cpp @@ -44,9 +44,12 @@ struct std::formatter struct std::formatter, CharT> { +private: + formatter, CharT> underlying; + public: constexpr void set_debug_format() - requires requires { this->underlying.set_debug_format(); } + requires requires { underlying.set_debug_format(); } { underlying.set_debug_format(); } @@ -60,9 +63,6 @@ struct std::formatter, CharT> { auto format(const test::proxy_reference& proxy, FormatContext& ctx) const { return underlying.format(static_cast(proxy), ctx); } - -private: - formatter, CharT> underlying; }; struct FormatAsX {}; 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 index 2263873c895..d742c9cb895 100644 --- 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 @@ -175,7 +175,11 @@ constexpr void check_single_view() { enum class CheckConstAdaptor : bool { no, yes }; +#ifdef __clang__ // TRANSITION, LLVM-104189 +template