From 7ac838857da15c5607a762770bcc653106479e99 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 20 Mar 2024 00:02:04 +0200 Subject: [PATCH 01/45] Fix `atomic_ref<16 bytes>::is_always_lock_free` (#4478) Co-authored-by: Stephan T. Lavavej --- stl/inc/atomic | 15 ++++++---- tests/std/tests/P0019R8_atomic_ref/env.lst | 3 ++ tests/std/tests/P0019R8_atomic_ref/test.cpp | 32 +++++++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index d96288e0131..18d1b3de576 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -1656,7 +1656,7 @@ _INLINE_VAR constexpr bool _Is_always_lock_free = _TypeSize <= 2 * sizeof(void*) #else // ^^^ _ATOMIC_HAS_DCAS / !_ATOMIC_HAS_DCAS vvv template _INLINE_VAR constexpr bool _Is_always_lock_free = _TypeSize <= sizeof(void*); -#endif // _ATOMIC_HAS_DCAS +#endif // ^^^ !_ATOMIC_HAS_DCAS ^^^ #endif // ^^^ break ABI ^^^ template > @@ -2179,7 +2179,7 @@ public: return sizeof(_Ty) <= 2 * sizeof(void*); #else // ^^^ _ATOMIC_HAS_DCAS / !_ATOMIC_HAS_DCAS vvv return sizeof(_Ty) <= sizeof(void*) || (sizeof(_Ty) <= 2 * sizeof(void*) && __std_atomic_has_cmpxchg16b()); -#endif // _ATOMIC_HAS_DCAS +#endif // ^^^ !_ATOMIC_HAS_DCAS ^^^ } #endif // ^^^ break ABI ^^^ @@ -2343,11 +2343,16 @@ public: atomic_ref& operator=(const atomic_ref&) = delete; - static constexpr bool is_always_lock_free = _Is_always_lock_free; - static constexpr bool _Is_potentially_lock_free = sizeof(_Ty) <= 2 * sizeof(void*) && (sizeof(_Ty) & (sizeof(_Ty) - 1)) == 0; + static constexpr bool is_always_lock_free = +#if _ATOMIC_HAS_DCAS + _Is_potentially_lock_free; +#else // ^^^ _ATOMIC_HAS_DCAS / !_ATOMIC_HAS_DCAS vvv + _Is_potentially_lock_free && sizeof(_Ty) <= sizeof(void*); +#endif // ^^^ !_ATOMIC_HAS_DCAS ^^^ + static constexpr size_t required_alignment = _Is_potentially_lock_free ? sizeof(_Ty) : alignof(_Ty); _NODISCARD bool is_lock_free() const noexcept { @@ -2359,7 +2364,7 @@ public: } else { return __std_atomic_has_cmpxchg16b() != 0; } -#endif // _ATOMIC_HAS_DCAS +#endif // ^^^ !_ATOMIC_HAS_DCAS ^^^ } void store(const _Ty _Value) const noexcept { diff --git a/tests/std/tests/P0019R8_atomic_ref/env.lst b/tests/std/tests/P0019R8_atomic_ref/env.lst index 351a8293d9d..b3f3ea48644 100644 --- a/tests/std/tests/P0019R8_atomic_ref/env.lst +++ b/tests/std/tests/P0019R8_atomic_ref/env.lst @@ -2,3 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception RUNALL_INCLUDE ..\usual_20_matrix.lst +RUNALL_CROSSLIST +* PM_CL="" +* PM_CL="/D_STD_ATOMIC_ALWAYS_USE_CMPXCHG16B=1 /DTEST_CMPXCHG16B" diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index c5ecce949ed..a687cc97da1 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -1,6 +1,12 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#if defined(TEST_CMPXCHG16B) && (defined(__clang__) || !defined(_M_X64)) +// Skip Clang because it would require the -mcx16 compiler option. +// Skip non-x64 because _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B is always 1 for ARM64, and is forbidden to be 1 for 32-bit. +int main() {} +#else // ^^^ skip test / run test vvv + #include #include #include @@ -373,6 +379,29 @@ void test_incomplete_associated_class_all() { // COMPILE-ONLY } #endif // ^^^ no workaround ^^^ +// GH-4472 ": With _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B defined to 1, +// atomic_ref<16 bytes> does not report is_lock_free and is_always_lock_free correctly" +void test_gh_4472() { + struct two_pointers_t { + void* left; + void* right; + }; + + alignas(std::atomic_ref::required_alignment) two_pointers_t two_pointers; + + static_assert(std::atomic_ref::required_alignment == sizeof(two_pointers_t)); + +#ifdef _WIN64 + static_assert(std::atomic_ref::is_always_lock_free == _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B); +#else + static_assert(std::atomic_ref::is_always_lock_free); +#endif + + // We expect tests to run on machines that support DCAS, which is required by Win8+. + std::atomic_ref ar{two_pointers}; + assert(ar.is_lock_free()); +} + int main() { test_ops(); test_ops(); @@ -425,4 +454,7 @@ int main() { test_ptr_ops(); test_gh_1497(); + test_gh_4472(); } + +#endif // ^^^ run test ^^^ From 9a4cda8cab88b77a0bb3d6bf561d305143f42748 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 20 Mar 2024 00:12:54 +0200 Subject: [PATCH 02/45] Remove attempt on unsized find vectorization... (#4486) Co-authored-by: Stephan T. Lavavej --- benchmarks/src/find_and_count.cpp | 19 ------- stl/inc/xutility | 83 +++++++++------------------ stl/src/vector_algorithms.cpp | 93 ++++++------------------------- 3 files changed, 43 insertions(+), 152 deletions(-) diff --git a/benchmarks/src/find_and_count.cpp b/benchmarks/src/find_and_count.cpp index 0b7561d4a9a..7b205aee6a0 100644 --- a/benchmarks/src/find_and_count.cpp +++ b/benchmarks/src/find_and_count.cpp @@ -42,31 +42,12 @@ BENCHMARK(bm); BENCHMARK(bm); BENCHMARK(bm); -BENCHMARK(bm); BENCHMARK(bm); BENCHMARK(bm); -BENCHMARK(bm); BENCHMARK(bm); BENCHMARK(bm); -BENCHMARK(bm); BENCHMARK(bm); -BENCHMARK(bm); -BENCHMARK(bm); -BENCHMARK(bm); - -BENCHMARK(bm); -BENCHMARK(bm); -BENCHMARK(bm); - -BENCHMARK(bm); -BENCHMARK(bm); -BENCHMARK(bm); - -BENCHMARK(bm); -BENCHMARK(bm); -BENCHMARK(bm); - BENCHMARK_MAIN(); diff --git a/stl/inc/xutility b/stl/inc/xutility index c946f9379d8..260c44f211f 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -90,11 +90,6 @@ const void* __stdcall __std_find_trivial_2(const void* _First, const void* _Last const void* __stdcall __std_find_trivial_4(const void* _First, const void* _Last, uint32_t _Val) noexcept; const void* __stdcall __std_find_trivial_8(const void* _First, const void* _Last, uint64_t _Val) noexcept; -const void* __stdcall __std_find_trivial_unsized_1(const void* _First, uint8_t _Val) noexcept; -const void* __stdcall __std_find_trivial_unsized_2(const void* _First, uint16_t _Val) noexcept; -const void* __stdcall __std_find_trivial_unsized_4(const void* _First, uint32_t _Val) noexcept; -const void* __stdcall __std_find_trivial_unsized_8(const void* _First, uint64_t _Val) noexcept; - const void* __stdcall __std_min_element_1(const void* _First, const void* _Last, bool _Signed) noexcept; const void* __stdcall __std_min_element_2(const void* _First, const void* _Last, bool _Signed) noexcept; const void* __stdcall __std_min_element_4(const void* _First, const void* _Last, bool _Signed) noexcept; @@ -170,27 +165,6 @@ _Ty* __std_find_trivial(_Ty* const _First, _Ty* const _Last, const _TVal _Val) n } } -template -_Ty* __std_find_trivial_unsized(_Ty* const _First, const _TVal _Val) noexcept { - if constexpr (is_pointer_v<_TVal> || is_null_pointer_v<_TVal>) { - return _STD __std_find_trivial_unsized(_First, reinterpret_cast(_Val)); - } else if constexpr (sizeof(_Ty) == 1) { - return const_cast<_Ty*>( - static_cast(::__std_find_trivial_unsized_1(_First, static_cast(_Val)))); - } else if constexpr (sizeof(_Ty) == 2) { - return const_cast<_Ty*>( - static_cast(::__std_find_trivial_unsized_2(_First, static_cast(_Val)))); - } else if constexpr (sizeof(_Ty) == 4) { - return const_cast<_Ty*>( - static_cast(::__std_find_trivial_unsized_4(_First, static_cast(_Val)))); - } else if constexpr (sizeof(_Ty) == 8) { - return const_cast<_Ty*>( - static_cast(::__std_find_trivial_unsized_8(_First, static_cast(_Val)))); - } else { - static_assert(_Always_false<_Ty>, "Unexpected size"); - } -} - template _Ty* __std_min_element(_Ty* const _First, _Ty* const _Last) noexcept { constexpr bool _Signed = is_signed_v<_Ty>; @@ -5975,8 +5949,14 @@ 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 = {}) { - constexpr bool _Is_sized = sized_sentinel_for<_Se, _It>; - if constexpr (_Vector_alg_in_find_is_safe<_It, _Ty> && _Sized_or_unreachable_sentinel_for<_Se, _It> + // 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>; + + 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) && same_as<_Pj, identity>) { if (!_STD is_constant_evaluated()) { if (!_STD _Could_compare_equal_to_value_type<_It>(_Val)) { @@ -5988,27 +5968,19 @@ namespace ranges { } } - using _Ptr_t = remove_reference_t<_Iter_ref_t<_It>>*; -#if _USE_STD_VECTOR_ALGORITHMS + using _Ptr_t = remove_reference_t<_Iter_ref_t<_It>>*; const auto _First_ptr = _STD _To_address(_First); _Ptr_t _Result; - +#if _USE_STD_VECTOR_ALGORITHMS if constexpr (_Is_sized) { + // When _Is_sized && _Single_byte_elements, prefer this over memchr() for performance const auto _Last_ptr = _First_ptr + (_Last - _First); - - _Result = _STD __std_find_trivial(_First_ptr, _Last_ptr, _Val); - } else { - _Result = _STD __std_find_trivial_unsized(_First_ptr, _Val); - } - - if constexpr (is_pointer_v<_It>) { - return _Result; - } else { - return _RANGES next(_STD move(_First), _Result - _First_ptr); - } -#else // ^^^ _USE_STD_VECTOR_ALGORITHMS / !_USE_STD_VECTOR_ALGORITHMS vvv - if constexpr (sizeof(_Iter_value_t<_It>) == 1) { + _Result = _STD __std_find_trivial(_First_ptr, _Last_ptr, _Val); + } else +#endif // ^^^ _USE_STD_VECTOR_ALGORITHMS ^^^ + { + _STL_INTERNAL_STATIC_ASSERT(_Single_byte_elements); size_t _Count; if constexpr (_Is_sized) { _Count = static_cast(_Last - _First); @@ -6016,21 +5988,20 @@ namespace ranges { _Count = SIZE_MAX; } - const auto _First_ptr = _STD to_address(_First); - const auto _Result = - static_cast<_Ptr_t>(_CSTD memchr(_First_ptr, static_cast(_Val), _Count)); - if (_Result) { - if constexpr (is_pointer_v<_It>) { - return _Result; - } else { - return _RANGES next(_STD move(_First), _Result - _First_ptr); + _Result = static_cast<_Ptr_t>(_CSTD memchr(_First_ptr, static_cast(_Val), _Count)); + + if constexpr (_Is_sized) { + if (_Result == nullptr) { + return _RANGES next(_STD move(_First), _Last); } - } else { - return _RANGES next(_STD move(_First), _Last); } } - // TRANSITION, DevCom-1614562: not trying wmemchr -#endif // ^^^ !_USE_STD_VECTOR_ALGORITHMS ^^^ + + if constexpr (is_pointer_v<_It>) { + return _Result; + } else { + return _RANGES next(_STD move(_First), _Result - _First_ptr); + } } } diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index bf9de5a308d..d1e2b654e4a 100644 --- a/stl/src/vector_algorithms.cpp +++ b/stl/src/vector_algorithms.cpp @@ -1837,79 +1837,9 @@ namespace { #endif // !_M_ARM64EC }; - // The below functions have exactly the same signature as the extern "C" functions, up to calling convention. - // This makes sure the template specialization is fused with the extern "C" function. - // In optimized builds it avoids an extra call, as this function is too large to inline. - - template - const void* __stdcall __std_find_trivial_unsized_impl(const void* _First, const _Ty _Val) noexcept { -#ifndef _M_ARM64EC - if ((reinterpret_cast(_First) & (sizeof(_Ty) - 1)) != 0) { - // _First isn't aligned to sizeof(_Ty), so we need to use the scalar fallback below. - // This can happen with 8-byte elements on x86's 4-aligned stack. It can also happen with packed structs. - } else if (_Use_avx2()) { - _Zeroupper_on_exit _Guard; // TRANSITION, DevCom-10331414 - - // We read by vector-sized pieces, and we align pointers to vector-sized boundary. - // From start partial piece we mask out matches that don't belong to the range. - // This makes sure we never cross page boundary, thus we read 'as if' sequentially. - constexpr size_t _Vector_pad_mask = 0x1F; - constexpr unsigned int _Full_mask = 0xFFFF'FFFF; - - const __m256i _Comparand = _Traits::_Set_avx(_Val); - const intptr_t _Pad_start = reinterpret_cast(_First) & _Vector_pad_mask; - const unsigned int _Mask = _Full_mask << _Pad_start; - _Advance_bytes(_First, -_Pad_start); - - __m256i _Data = _mm256_load_si256(static_cast(_First)); - unsigned int _Bingo = static_cast(_mm256_movemask_epi8(_Traits::_Cmp_avx(_Data, _Comparand))); - - _Bingo &= _Mask; - - for (;;) { - if (_Bingo != 0) { - unsigned long _Offset = _tzcnt_u32(_Bingo); - _Advance_bytes(_First, _Offset); - return _First; - } - - _Advance_bytes(_First, 32); - - _Data = _mm256_load_si256(static_cast(_First)); - _Bingo = static_cast(_mm256_movemask_epi8(_Traits::_Cmp_avx(_Data, _Comparand))); - } - } else if (_Traits::_Sse_available()) { - // We read by vector-sized pieces, and we align pointers to vector-sized boundary. - // From start partial piece we mask out matches that don't belong to the range. - // This makes sure we never cross page boundary, thus we read 'as if' sequentially. - constexpr size_t _Vector_pad_mask = 0xF; - constexpr unsigned int _Full_mask = 0xFFFF; - - const __m128i _Comparand = _Traits::_Set_sse(_Val); - const intptr_t _Pad_start = reinterpret_cast(_First) & _Vector_pad_mask; - const unsigned int _Mask = _Full_mask << _Pad_start; - _Advance_bytes(_First, -_Pad_start); - - __m128i _Data = _mm_load_si128(static_cast(_First)); - unsigned int _Bingo = static_cast(_mm_movemask_epi8(_Traits::_Cmp_sse(_Data, _Comparand))); - - _Bingo &= _Mask; - - for (;;) { - if (_Bingo != 0) { - unsigned long _Offset; - _BitScanForward(&_Offset, _Bingo); // lgtm [cpp/conditionallyuninitializedvariable] - _Advance_bytes(_First, _Offset); - return _First; - } - - _Advance_bytes(_First, 16); - - _Data = _mm_load_si128(static_cast(_First)); - _Bingo = static_cast(_mm_movemask_epi8(_Traits::_Cmp_sse(_Data, _Comparand))); - } - } -#endif // !_M_ARM64EC + // TRANSITION, ABI: used only in functions preserved for binary compatibility + template + const void* __std_find_trivial_unsized_impl(const void* const _First, const _Ty _Val) noexcept { auto _Ptr = static_cast(_First); while (*_Ptr != _Val) { ++_Ptr; @@ -1917,6 +1847,10 @@ namespace { return _Ptr; } + // The below functions have exactly the same signature as the extern "C" functions, up to calling convention. + // This makes sure the template specialization can be fused with the extern "C" function. + // In optimized builds it avoids an extra call, as these functions are too large to inline. + template const void* __stdcall __std_find_trivial_impl(const void* _First, const void* _Last, _Ty _Val) noexcept { #ifndef _M_ARM64EC @@ -2079,20 +2013,25 @@ namespace { extern "C" { +// TRANSITION, ABI: preserved for binary compatibility const void* __stdcall __std_find_trivial_unsized_1(const void* const _First, const uint8_t _Val) noexcept { - return __std_find_trivial_unsized_impl<_Find_traits_1>(_First, _Val); + return memchr(_First, _Val, SIZE_MAX); } +// TRANSITION, ABI: preserved for binary compatibility const void* __stdcall __std_find_trivial_unsized_2(const void* const _First, const uint16_t _Val) noexcept { - return __std_find_trivial_unsized_impl<_Find_traits_2>(_First, _Val); + // TRANSITION, DevCom-1614562: not trying wmemchr + return __std_find_trivial_unsized_impl(_First, _Val); } +// TRANSITION, ABI: preserved for binary compatibility const void* __stdcall __std_find_trivial_unsized_4(const void* const _First, const uint32_t _Val) noexcept { - return __std_find_trivial_unsized_impl<_Find_traits_4>(_First, _Val); + return __std_find_trivial_unsized_impl(_First, _Val); } +// TRANSITION, ABI: preserved for binary compatibility const void* __stdcall __std_find_trivial_unsized_8(const void* const _First, const uint64_t _Val) noexcept { - return __std_find_trivial_unsized_impl<_Find_traits_8>(_First, _Val); + return __std_find_trivial_unsized_impl(_First, _Val); } const void* __stdcall __std_find_trivial_1( From 2175098dee5c987a0c7ab8d047804d770eacfbbb Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 19 Mar 2024 15:20:56 -0700 Subject: [PATCH 03/45] Standard Library Modules: Fix warning C4365 (signed/unsigned mismatch) with `/ZI` (#4487) --- stl/inc/yvals.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/stl/inc/yvals.h b/stl/inc/yvals.h index 9428b35aaeb..d2201390f57 100644 --- a/stl/inc/yvals.h +++ b/stl/inc/yvals.h @@ -172,8 +172,10 @@ _STL_DISABLE_CLANG_WARNINGS #ifndef _STL_CRT_SECURE_INVALID_PARAMETER #ifdef _STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER #define _STL_CRT_SECURE_INVALID_PARAMETER(expr) _CSTD abort() -#elif defined(_DEBUG) // avoid emitting unused long strings for function names; see GH-1956 -#define _STL_CRT_SECURE_INVALID_PARAMETER(expr) ::_invalid_parameter(_CRT_WIDE(#expr), L"", __FILEW__, __LINE__, 0) +#elif defined(_DEBUG) // Avoid emitting unused long strings for function names; see GH-1956. +// static_cast(__LINE__) avoids warning C4365 (signed/unsigned mismatch) with the /ZI compiler option. +#define _STL_CRT_SECURE_INVALID_PARAMETER(expr) \ + ::_invalid_parameter(_CRT_WIDE(#expr), L"", __FILEW__, static_cast(__LINE__), 0) #else // ^^^ defined(_DEBUG) / !defined(_DEBUG) vvv #define _STL_CRT_SECURE_INVALID_PARAMETER(expr) _CRT_SECURE_INVALID_PARAMETER(expr) #endif // ^^^ !defined(_DEBUG) ^^^ @@ -465,11 +467,7 @@ class _CRTIMP2_PURE_IMPORT _EmptyLockit { // empty lock class used for bin compa } \ } -#ifdef _DEBUG -#define _RAISE(x) _invoke_watson(_CRT_WIDE(#x), __FUNCTIONW__, __FILEW__, __LINE__, 0) -#else #define _RAISE(x) _invoke_watson(nullptr, nullptr, nullptr, 0, 0) -#endif #define _RERAISE #define _THROW(...) (__VA_ARGS__)._Raise() From 4787efeae109b601d0f04edf3083325b4c9fd4ed Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 20 Mar 2024 06:57:56 +0800 Subject: [PATCH 04/45] ``, ``: Make `tuple`-related functions ADL-proof (#4488) --- stl/inc/tuple | 10 +- stl/inc/utility | 3 +- .../tests/Dev11_0000000_tuple_cat/test.cpp | 314 ++++++++++++------ 3 files changed, 222 insertions(+), 105 deletions(-) diff --git a/stl/inc/tuple b/stl/inc/tuple index f5e120cf39f..c49a9205c5f 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -1053,7 +1053,7 @@ _NODISCARD constexpr typename _Tuple_cat1<_Tuples...>::_Ret tuple_cat(_Tuples&&. using _Ret = typename _Cat1::_Ret; using _Kx_seq = typename _Cat1::_Kx_seq; using _Ix_seq = typename _Cat1::_Ix_seq; - return _Tuple_cat<_Ret>(_Kx_seq{}, _Ix_seq{}, _STD forward_as_tuple(_STD forward<_Tuples>(_Tpls)...)); + return _STD _Tuple_cat<_Ret>(_Kx_seq{}, _Ix_seq{}, _STD forward_as_tuple(_STD forward<_Tuples>(_Tpls)...)); } #if _HAS_CXX17 @@ -1073,9 +1073,9 @@ _EXPORT_STD template _EXPORT_STD template #endif // ^^^ !_HAS_CXX23 ^^^ constexpr decltype(auto) apply(_Callable&& _Obj, _Tuple&& _Tpl) noexcept( - noexcept(_Apply_impl(_STD forward<_Callable>(_Obj), _STD forward<_Tuple>(_Tpl), + noexcept(_STD _Apply_impl(_STD forward<_Callable>(_Obj), _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}))) { - return _Apply_impl(_STD forward<_Callable>(_Obj), _STD forward<_Tuple>(_Tpl), + return _STD _Apply_impl(_STD forward<_Callable>(_Obj), _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}); } @@ -1097,10 +1097,10 @@ _EXPORT_STD template #else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv _EXPORT_STD template #endif // ^^^ !_HAS_CXX23 ^^^ -_NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) noexcept(noexcept(_Make_from_tuple_impl<_Ty>( +_NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) noexcept(noexcept(_STD _Make_from_tuple_impl<_Ty>( _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}))) /* strengthened */ { // construct _Ty from the elements of _Tpl - return _Make_from_tuple_impl<_Ty>( + return _STD _Make_from_tuple_impl<_Ty>( _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}); } #endif // _HAS_CXX17 diff --git a/stl/inc/utility b/stl/inc/utility index 3206659c1be..458091fb313 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -304,7 +304,8 @@ struct pair { // store a pair of values template constexpr pair(_Tuple1& _Val1, _Tuple2& _Val2, index_sequence<_Indices1...>, index_sequence<_Indices2...>) - : first(_Tuple_get<_Indices1>(_STD move(_Val1))...), second(_Tuple_get<_Indices2>(_STD move(_Val2))...) {} + : first(_STD _Tuple_get<_Indices1>(_STD move(_Val1))...), + second(_STD _Tuple_get<_Indices2>(_STD move(_Val2))...) {} template _CONSTEXPR20 pair(piecewise_construct_t, tuple<_Types1...> _Val1, tuple<_Types2...> _Val2) diff --git a/tests/std/tests/Dev11_0000000_tuple_cat/test.cpp b/tests/std/tests/Dev11_0000000_tuple_cat/test.cpp index 78a23775861..dec106b5eae 100644 --- a/tests/std/tests/Dev11_0000000_tuple_cat/test.cpp +++ b/tests/std/tests/Dev11_0000000_tuple_cat/test.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -10,6 +11,10 @@ #include #include +#if _HAS_CXX17 +#include +#endif // _HAS_CXX17 + #if _HAS_CXX20 #include #include @@ -21,8 +26,26 @@ using namespace std; #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) +#if _HAS_CXX17 +#define CONSTEXPR17 constexpr +#else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv +#define CONSTEXPR17 inline +#endif // ^^^ !_HAS_CXX17 ^^^ + +#if _HAS_CXX20 +#define CONSTEXPR20 constexpr +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +#define CONSTEXPR20 inline +#endif // ^^^ !_HAS_CXX20 ^^^ + +#if _HAS_CXX23 +#define CONSTEXPR23 constexpr +#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv +#define CONSTEXPR23 inline +#endif // ^^^ !_HAS_CXX23 ^^^ + template