From d283baedeac851b940357e63bc7c2fbe9d7d7440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 12 Nov 2025 14:49:35 +0100 Subject: [PATCH 1/9] Add tests. --- tests/std/test.lst | 1 + .../P3016R6_inconsistent_begin_end/env.lst | 4 ++ .../P3016R6_inconsistent_begin_end/test.cpp | 65 +++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 tests/std/tests/P3016R6_inconsistent_begin_end/env.lst create mode 100644 tests/std/tests/P3016R6_inconsistent_begin_end/test.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index c502981b96d..41a9aa8da45 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -720,6 +720,7 @@ tests\P2693R1_text_formatting_header_stacktrace tests\P2693R1_text_formatting_header_thread tests\P2693R1_text_formatting_stacktrace tests\P2693R1_text_formatting_thread_id +tests\P3016R6_inconsistent_begin_end tests\P3107R5_enabled_specializations tests\P3349R1_contiguous_iterators_to_pointers tests\P3503R3_packaged_task_promise_with_allocator diff --git a/tests/std/tests/P3016R6_inconsistent_begin_end/env.lst b/tests/std/tests/P3016R6_inconsistent_begin_end/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P3016R6_inconsistent_begin_end/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P3016R6_inconsistent_begin_end/test.cpp b/tests/std/tests/P3016R6_inconsistent_begin_end/test.cpp new file mode 100644 index 00000000000..8e5080a6fb7 --- /dev/null +++ b/tests/std/tests/P3016R6_inconsistent_begin_end/test.cpp @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +namespace my { + + template + void begin(std::initializer_list); + + template + void end(std::initializer_list); + + template + void empty(std::initializer_list); + + template + void data(std::initializer_list); +} + + +int main() { + { + // Check that free functions in std can't be invoked with braced-initializer-list. + // If they could be invoked, the following expressions would be ambiguous between std:: and my:: + using namespace std; + using namespace my; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } + + { + // Check that free functions in std still can be invoked on std::initializer_list + std::initializer_list il = {1, 2, 3}; + + using namespace std; + (void) begin(il); + (void) cbegin(il); + (void) end(il); + (void) cend(il); + (void) size(il); + (void) empty(il); + (void) data(il); + } + + { + // Check that free functions in std can be invoked on std::valarray + std::valarray v{1}; + + using namespace std; + (void) begin(v); + (void) cbegin(v); // Did not compile before P3016R6 + (void) end(v); + (void) cend(v); // Did not compile before P3016R6 + (void) size(v); + // There are no members 'empty' and 'data' of valarray + // (void) empty(il); + // (void) data(il); + } +} From 498ee1cef4e1d6e9e9dfb86bc74fc064a80dc901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 12 Nov 2025 14:55:04 +0100 Subject: [PATCH 2/9] Remove free function overloads for std::initializer_list --- stl/inc/initializer_list | 17 ++++++++--------- stl/inc/xutility | 10 ---------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/stl/inc/initializer_list b/stl/inc/initializer_list index b5d6ae7370e..852c8c32149 100644 --- a/stl/inc/initializer_list +++ b/stl/inc/initializer_list @@ -51,20 +51,19 @@ public: return static_cast(_Last - _First); } + _NODISCARD constexpr bool empty() const noexcept { + return size() == 0; + } + + _NODISCARD constexpr const _Elem* data() const noexcept { + return begin(); + } + private: const _Elem* _First; const _Elem* _Last; }; -_EXPORT_STD template -_NODISCARD constexpr const _Elem* begin(initializer_list<_Elem> _Ilist) noexcept { - return _Ilist.begin(); -} - -_EXPORT_STD template -_NODISCARD constexpr const _Elem* end(initializer_list<_Elem> _Ilist) noexcept { - return _Ilist.end(); -} _STD_END // TRANSITION, non-_Ugly attribute tokens diff --git a/stl/inc/xutility b/stl/inc/xutility index bbaf4357d91..7815db74d9b 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -2283,11 +2283,6 @@ _NODISCARD_EMPTY_NON_MEMBER constexpr bool empty(const _Ty (&)[_Size]) noexcept return false; } -_EXPORT_STD template -_NODISCARD_EMPTY_NON_MEMBER constexpr bool empty(initializer_list<_Elem> _Ilist) noexcept { - return _Ilist.size() == 0; -} - _EXPORT_STD template _NODISCARD constexpr auto data(_Container& _Cont) noexcept(noexcept(_Cont.data())) /* strengthened */ -> decltype(_Cont.data()) { @@ -2305,11 +2300,6 @@ _NODISCARD constexpr _Ty* data(_Ty (&_Array)[_Size]) noexcept { return _Array; } -_EXPORT_STD template -_NODISCARD constexpr const _Elem* data(initializer_list<_Elem> _Ilist) noexcept { - return _Ilist.begin(); -} - #if _HAS_CXX20 #if _HAS_CXX23 _EXPORT_STD template From 497704e913a3e17cffdea7a0f470db0d94f4d2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 12 Nov 2025 14:55:35 +0100 Subject: [PATCH 3/9] Change begin/end for valarray from friend free functions to members. --- stl/inc/valarray | 50 +++++++++++++++++------------------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/stl/inc/valarray b/stl/inc/valarray index a6a0909d9a8..bef247d8aa7 100644 --- a/stl/inc/valarray +++ b/stl/inc/valarray @@ -59,19 +59,9 @@ class valarray { // store array with various indexing options public: friend _Tidy_deallocate_guard; - template - friend _Ty2* begin(valarray<_Ty2>& _Array) noexcept /* strengthened */; - - template - friend const _Ty2* begin(const valarray<_Ty2>& _Array) noexcept /* strengthened */; - - template - friend _Ty2* end(valarray<_Ty2>& _Array) noexcept /* strengthened */; - - template - friend const _Ty2* end(const valarray<_Ty2>& _Array) noexcept /* strengthened */; - using value_type = _Ty; + using iterator = _Ty*; + using const_iterator = const _Ty*; valarray() = default; // construct empty valarray @@ -411,6 +401,22 @@ public: return _Mysize; } + _NODISCARD iterator begin() noexcept /* strengthened */ { + return _Myptr; + } + + _NODISCARD const_iterator begin() const noexcept /* strengthened */ { + return _Myptr; + } + + _NODISCARD iterator end() noexcept /* strengthened */ { + return _Myptr + _Mysize; + } + + _NODISCARD const_iterator end() const noexcept /* strengthened */ { + return _Myptr + _Mysize; + } + _NODISCARD const _Ty& operator[](size_t _Off) const noexcept /* strengthened */ { #if _MSVC_STL_HARDENING_VALARRAY || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Off < _Mysize, "valarray subscript out of range"); @@ -612,26 +618,6 @@ void swap(valarray<_Ty>& _Left, valarray<_Ty>& _Right) noexcept { _Left.swap(_Right); } -_EXPORT_STD template -_NODISCARD _Ty* begin(valarray<_Ty>& _Array) noexcept /* strengthened */ { - return _Array._Myptr; -} - -_EXPORT_STD template -_NODISCARD const _Ty* begin(const valarray<_Ty>& _Array) noexcept /* strengthened */ { - return _Array._Myptr; -} - -_EXPORT_STD template -_NODISCARD _Ty* end(valarray<_Ty>& _Array) noexcept /* strengthened */ { - return _Array._Myptr + _Array.size(); -} - -_EXPORT_STD template -_NODISCARD const _Ty* end(const valarray<_Ty>& _Array) noexcept /* strengthened */ { - return _Array._Myptr + _Array.size(); -} - _EXPORT_STD template _NODISCARD valarray<_Ty> operator*(const valarray<_Ty>& _Left, const typename valarray<_Ty>::value_type& _Right) { const size_t _Size = _Left.size(); From 0887c8d7f62e74decc6e9e787f1a6e54a7c9c496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 12 Nov 2025 14:56:07 +0100 Subject: [PATCH 4/9] Add feature test macros __cpp_lib_initializer_list and __cpp_lib_valarray --- stl/inc/yvals_core.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 0ccf71729ed..ca87e407b8a 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -80,6 +80,7 @@ // (__cpp_lib_freestanding_algorithm and __cpp_lib_freestanding_array only) // P2937R0 Freestanding Library: Remove strtok // P2968R2 Make std::ignore A First-Class Object +// P3016R6 Resolve Inconsistencies In begin/end For valarray And Braced Initializer Lists // P3223R2 Making istream::ignore() Less Surprising // P3323R1 Forbid atomic, Specify atomic_ref // (for atomic) @@ -1833,6 +1834,11 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_unreachable 202202L #endif // _HAS_CXX23 +// C++26 +#define __cpp_lib_initializer_list 202511L +#define __cpp_lib_valarray 202511L + + // macros with language mode sensitivity #if _HAS_CXX20 #define __cpp_lib_array_constexpr 201811L // P1032R1 Miscellaneous constexpr From 9a56b7e4ab1aca2c0f3c4ee295a9a54221f068be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 12 Nov 2025 15:21:53 +0100 Subject: [PATCH 5/9] Remove extra whitespace. --- stl/inc/yvals_core.h | 1 - 1 file changed, 1 deletion(-) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index ca87e407b8a..e299b61b6a4 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1838,7 +1838,6 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_initializer_list 202511L #define __cpp_lib_valarray 202511L - // macros with language mode sensitivity #if _HAS_CXX20 #define __cpp_lib_array_constexpr 201811L // P1032R1 Miscellaneous constexpr From ecc409ad93a7f80be86164011a9412fe194b3a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 12 Nov 2025 15:32:39 +0100 Subject: [PATCH 6/9] Fix incorrect formatting. --- stl/inc/valarray | 4 ++-- .../P3016R6_inconsistent_begin_end/test.cpp | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/stl/inc/valarray b/stl/inc/valarray index bef247d8aa7..73a6a0e8fa8 100644 --- a/stl/inc/valarray +++ b/stl/inc/valarray @@ -59,8 +59,8 @@ class valarray { // store array with various indexing options public: friend _Tidy_deallocate_guard; - using value_type = _Ty; - using iterator = _Ty*; + using value_type = _Ty; + using iterator = _Ty*; using const_iterator = const _Ty*; valarray() = default; // construct empty valarray diff --git a/tests/std/tests/P3016R6_inconsistent_begin_end/test.cpp b/tests/std/tests/P3016R6_inconsistent_begin_end/test.cpp index 8e5080a6fb7..9d99422f908 100644 --- a/tests/std/tests/P3016R6_inconsistent_begin_end/test.cpp +++ b/tests/std/tests/P3016R6_inconsistent_begin_end/test.cpp @@ -1,25 +1,25 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include #include +#include #include #include namespace my { - - template + + template void begin(std::initializer_list); - template + template void end(std::initializer_list); - template + template void empty(std::initializer_list); - template + template void data(std::initializer_list); -} +} // namespace my int main() { @@ -33,8 +33,8 @@ int main() { static_assert(std::is_same_v); static_assert(std::is_same_v); } - - { + + { // Check that free functions in std still can be invoked on std::initializer_list std::initializer_list il = {1, 2, 3}; From b9c607a2a5648fba205dfaae624b76f2f5d093f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 12 Nov 2025 18:59:29 +0100 Subject: [PATCH 7/9] Update tests to unconditionally support P3016R6. Only check that begin(initializer_list) is constexpr in C++17 onwards (tests/Dev11_1074023_constexpr). Mark libc++ std/language.support/support.initlist/support.initlist.range/begin_end.pass.cpp as known FAIL. --- tests/libcxx/expected_results.txt | 3 +++ tests/std/tests/Dev11_1074023_constexpr/test.cpp | 2 ++ 2 files changed, 5 insertions(+) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 343abccc27a..156412a9bc1 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -142,6 +142,9 @@ std/language.support/support.limits/support.limits.general/mdspan.version.compil # libc++ has not implemented P2937R0: "Freestanding Library: Remove strtok" std/language.support/support.limits/support.limits.general/cstring.version.compile.pass.cpp FAIL +# libc++ has not implemented P3016R6: "Resolve Inconsistencies In begin/end For valarray And Braced Initializer Lists" +std/language.support/support.initlist/support.initlist.range/begin_end.pass.cpp FAIL + # libc++ has not implemented P3323R1: "Forbid atomic, Specify atomic_ref" std/atomics/atomics.ref/member_types.compile.pass.cpp FAIL diff --git a/tests/std/tests/Dev11_1074023_constexpr/test.cpp b/tests/std/tests/Dev11_1074023_constexpr/test.cpp index d9b87f87247..47092a0a47e 100644 --- a/tests/std/tests/Dev11_1074023_constexpr/test.cpp +++ b/tests/std/tests/Dev11_1074023_constexpr/test.cpp @@ -53,7 +53,9 @@ constexpr auto int64_max = numeric_limits::max(); constexpr initializer_list il; STATIC_ASSERT(il.size() == 0); STATIC_ASSERT(il.begin() == il.end()); +#if _HAS_CXX17 STATIC_ASSERT(begin(il) == end(il)); +#endif // _HAS_CXX17 // TRANSITION, // constexpr error_category() noexcept; From 1f660da4f4e45f158faab11ac0706364db6cf671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Thu, 13 Nov 2025 13:25:25 +0100 Subject: [PATCH 8/9] Correct placement of feature test macros in yvals_core.h --- stl/inc/yvals_core.h | 6 ++---- .../VSO_0157762_feature_test_macros/test.compile.pass.cpp | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index e299b61b6a4..97dc0808a70 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1609,6 +1609,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_freestanding_tuple 202306L #define __cpp_lib_freestanding_utility 202306L #define __cpp_lib_generic_associative_lookup 201304L +#define __cpp_lib_initializer_list 202511L #define __cpp_lib_integer_sequence 201304L #define __cpp_lib_integral_constant_callable 201304L #define __cpp_lib_is_final 201402L @@ -1626,6 +1627,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_transformation_trait_aliases 201304L #define __cpp_lib_tuple_element_t 201402L #define __cpp_lib_tuples_by_type 201304L +#define __cpp_lib_valarray 202511L // C++17 #define __cpp_lib_addressof_constexpr 201603L @@ -1834,10 +1836,6 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_unreachable 202202L #endif // _HAS_CXX23 -// C++26 -#define __cpp_lib_initializer_list 202511L -#define __cpp_lib_valarray 202511L - // macros with language mode sensitivity #if _HAS_CXX20 #define __cpp_lib_array_constexpr 201811L // P1032R1 Miscellaneous constexpr diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index fe5fbd82a9a..67578b87396 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -1048,3 +1048,7 @@ STATIC_ASSERT(__cpp_lib_variant == 202102L); #endif STATIC_ASSERT(__cpp_lib_void_t == 201411L); + +STATIC_ASSERT(__cpp_lib_initializer_list == 202511L); + +STATIC_ASSERT(__cpp_lib_valarray == 202511L); From dcf8058dcfdb86a10af7f7ae2fe71f9cb1b8d714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Thu, 13 Nov 2025 13:29:04 +0100 Subject: [PATCH 9/9] Add constexpr tests for std::initializer_list and iteration over braced-init-list --- .../P3016R6_inconsistent_begin_end/env.lst | 2 +- .../P3016R6_inconsistent_begin_end/test.cpp | 96 ++++++++++++------- 2 files changed, 60 insertions(+), 38 deletions(-) diff --git a/tests/std/tests/P3016R6_inconsistent_begin_end/env.lst b/tests/std/tests/P3016R6_inconsistent_begin_end/env.lst index 642f530ffad..19f025bd0e6 100644 --- a/tests/std/tests/P3016R6_inconsistent_begin_end/env.lst +++ b/tests/std/tests/P3016R6_inconsistent_begin_end/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\usual_latest_matrix.lst +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/P3016R6_inconsistent_begin_end/test.cpp b/tests/std/tests/P3016R6_inconsistent_begin_end/test.cpp index 9d99422f908..ab63fa58fe5 100644 --- a/tests/std/tests/P3016R6_inconsistent_begin_end/test.cpp +++ b/tests/std/tests/P3016R6_inconsistent_begin_end/test.cpp @@ -6,6 +6,8 @@ #include #include +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + namespace my { template @@ -21,45 +23,65 @@ namespace my { void data(std::initializer_list); } // namespace my +_CONSTEXPR17 bool test_initializer_list() { + // Check that free functions in std still can be invoked on std::initializer_list + std::initializer_list il = {1, 2, 3}; -int main() { - { - // Check that free functions in std can't be invoked with braced-initializer-list. - // If they could be invoked, the following expressions would be ambiguous between std:: and my:: - using namespace std; - using namespace my; - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } + using namespace std; + (void) begin(il); + (void) cbegin(il); + (void) end(il); + (void) cend(il); + (void) size(il); + (void) empty(il); + (void) data(il); - { - // Check that free functions in std still can be invoked on std::initializer_list - std::initializer_list il = {1, 2, 3}; - - using namespace std; - (void) begin(il); - (void) cbegin(il); - (void) end(il); - (void) cend(il); - (void) size(il); - (void) empty(il); - (void) data(il); - } + return true; +} + +bool test_valarray() { + // Check that free functions in std can be invoked on std::valarray + std::valarray v{1}; - { - // Check that free functions in std can be invoked on std::valarray - std::valarray v{1}; - - using namespace std; - (void) begin(v); - (void) cbegin(v); // Did not compile before P3016R6 - (void) end(v); - (void) cend(v); // Did not compile before P3016R6 - (void) size(v); - // There are no members 'empty' and 'data' of valarray - // (void) empty(il); - // (void) data(il); + using namespace std; + (void) begin(v); + (void) cbegin(v); // Did not compile before P3016R6 + (void) end(v); + (void) cend(v); // Did not compile before P3016R6 + (void) size(v); + // There are no members 'empty' and 'data' of valarray + // (void) empty(il); + // (void) data(il); + + return true; +} + +constexpr bool test_braced_init_list_iteration() { + int sum = 0; + for (int n : {1, 2, 3, 4}) { + sum += n; } + return sum == 10; +} + + +int main() { + // Check that free functions in std can't be invoked with braced-initializer-list. + // If they could be invoked, the following expressions would be ambiguous between std:: and my:: + using namespace std; + using namespace my; + STATIC_ASSERT(std::is_same_v); + STATIC_ASSERT(std::is_same_v); + STATIC_ASSERT(std::is_same_v); + STATIC_ASSERT(std::is_same_v); + + test_initializer_list(); + test_valarray(); + test_braced_init_list_iteration(); + +#if _HAS_CXX17 + STATIC_ASSERT(test_initializer_list()); +#endif // _HAS_CXX17 + // STATIC_ASSERT(test_valarray()); // valarray is not literal + STATIC_ASSERT(test_braced_init_list_iteration()); }