https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/78157
>From 01f0ed005f2037fa4a4ec64ad5e1a114da1f5e99 Mon Sep 17 00:00:00 2001 From: Zingam <zin...@outlook.com> Date: Thu, 11 Jan 2024 10:42:55 +0200 Subject: [PATCH 1/9] [libc++][span] P2447R4: `std::span` over an initializer list Implements: https://wg21.link/P2447R6 - https://eel.is/c++draft/span.syn - https://eel.is/c++draft/span.overview - https://eel.is/c++draft/span.cons - https://eel.is/c++draft/diff --- libcxx/docs/ReleaseNotes/18.rst | 1 + libcxx/docs/Status/Cxx2cPapers.csv | 2 +- libcxx/include/span | 18 +++ .../views/views.span/span.cons/array.pass.cpp | 4 + .../initializer_list.assert.pass.cpp | 45 ++++++ .../span.cons/initializer_list.pass.cpp | 131 ++++++++++++++++-- .../span.cons/iterator_len.verify.cpp | 24 +++- .../generate_feature_test_macro_components.py | 1 - 8 files changed, 204 insertions(+), 22 deletions(-) create mode 100644 libcxx/test/std/containers/views/views.span/span.cons/initializer_list.assert.pass.cpp diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst index 62a1fec627d0ca..bf0ef8d447a3a5 100644 --- a/libcxx/docs/ReleaseNotes/18.rst +++ b/libcxx/docs/ReleaseNotes/18.rst @@ -60,6 +60,7 @@ Implemented Papers - P0521R0 - Proposed Resolution for CA 14 (``shared_ptr`` ``use_count/unique``) - P1759R6 - Native handles and file streams - P2517R1 - Add a conditional ``noexcept`` specification to ``std::apply`` +- P2447R6 - ``span`` over initializer list Improvements and New Features diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 5701717f39766c..2a7ee46816e9d9 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -34,7 +34,7 @@ "`P2918R2 <https://wg21.link/P2918R2>`__","LWG","Runtime format strings II","Kona November 2023","|Complete|","18.0","|format|" "`P2909R4 <https://wg21.link/P2909R4>`__","LWG","Fix formatting of code units as integers (Dude, where’s my ``char``?)","Kona November 2023","|Complete|","18.0","|format| |DR|" "`P0952R2 <https://wg21.link/P0952R2>`__","LWG","A new specification for ``std::generate_canonical``","Kona November 2023","","","" -"`P2447R6 <https://wg21.link/P2447R6>`__","LWG","``std::span`` over an initializer list","Kona November 2023","","","" +"`P2447R6 <https://wg21.link/P2447R6>`__","LWG","``std::span`` over an initializer list","Kona November 2023","|Complete","18.0","" "`P2821R5 <https://wg21.link/P2821R5>`__","LWG","``span.at()``","Kona November 2023","|Complete|","18.0","" "`P2868R3 <https://wg21.link/P2868R3>`__","LWG","Remove Deprecated ``std::allocator`` Typedef From C++26","Kona November 2023","","","" "`P2870R3 <https://wg21.link/P2870R3>`__","LWG","Remove ``basic_string::reserve()`` From C++26","Kona November 2023","|Complete|","18.0","" diff --git a/libcxx/include/span b/libcxx/include/span index 007a32597f965b..7ce0faa9457099 100644 --- a/libcxx/include/span +++ b/libcxx/include/span @@ -68,6 +68,7 @@ public: constexpr span(const array<value_type, N>& arr) noexcept; template<class R> constexpr explicit(Extent != dynamic_extent) span(R&& r); + constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il); // Since C++26 constexpr span(const span& other) noexcept = default; template <class OtherElementType, size_t OtherExtent> constexpr explicit(Extent != dynamic_extent) span(const span<OtherElementType, OtherExtent>& s) noexcept; @@ -228,6 +229,15 @@ public: requires(_Sz == 0) _LIBCPP_HIDE_FROM_ABI constexpr span() noexcept : __data_{nullptr} {} +# if _LIBCPP_STD_VER >= 26 + _LIBCPP_HIDE_FROM_ABI constexpr explicit span(std::initializer_list<value_type> __il) + requires is_const_v<element_type> + : __data_{__il.begin()} { + // static_assert(false, "constructor (static extent) called"); + _LIBCPP_ASSERT_INTERNAL(_Extent == __il.size(), "Size mismatch in span's constructor _Extent != __il.size()."); + } +# endif + constexpr span(const span&) noexcept = default; constexpr span& operator=(const span&) noexcept = default; @@ -397,6 +407,14 @@ public: // [span.cons], span constructors, copy, assignment, and destructor _LIBCPP_HIDE_FROM_ABI constexpr span() noexcept : __data_{nullptr}, __size_{0} {} +# if _LIBCPP_STD_VER >= 26 + _LIBCPP_HIDE_FROM_ABI constexpr span(std::initializer_list<value_type> __il) + requires is_const_v<element_type> + : __data_{__il.begin()}, __size_{__il.size()} { + // static_assert(false, "constructor (dynamic extent) called"); + } +# endif + constexpr span(const span&) noexcept = default; constexpr span& operator=(const span&) noexcept = default; diff --git a/libcxx/test/std/containers/views/views.span/span.cons/array.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/array.pass.cpp index 8fa7692c3b6370..b01fdda84789ce 100644 --- a/libcxx/test/std/containers/views/views.span/span.cons/array.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/array.pass.cpp @@ -94,7 +94,11 @@ constexpr bool testSpan() assert(s4.data() == val && s4.size() == 2); std::span<const int> s5 = {{1,2}}; +#if TEST_STD_VER >= 26 + std::span<const int, 2> s6({1,2}); +#else std::span<const int, 2> s6 = {{1,2}}; +#endif assert(s5.size() == 2); // and it dangles assert(s6.size() == 2); // and it dangles diff --git a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.assert.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.assert.pass.cpp new file mode 100644 index 00000000000000..ecf3f00e833e51 --- /dev/null +++ b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.assert.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 + +// REQUIRES: has-unix-headers +// REQUIRES: libcpp-hardening-mode={{extensive|debug}} +// XFAIL: availability-verbose_abort-missing + +// <span> + +// constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il); // Since C++26 + +#include <cassert> +#include <span> +#include <initializer_list> + +#include "check_assertion.h" + +// template <std::size_t N> +// void test_runtime_assertion(std::span<const int, N> sp) { +// static_assert(std::dynamic_extent != sp.extent); +// } + +bool test() { + TEST_LIBCPP_ASSERT_FAILURE( + (std::span<const int, 4>({1, 2, 3, 9084, 5})), "Size mismatch in span's constructor _Extent != __il.size()."); + TEST_LIBCPP_ASSERT_FAILURE((std::span<const int, 4>(std::initializer_list<int>{1, 2, 3, 9084, 5})), + "Size mismatch in span's constructor _Extent != __il.size()."); + // TEST_LIBCPP_ASSERT_FAILURE((test_runtime_assertion(std::span<const int, 4>({1, 2, 3, 9084, 0}))), + // "Size mismatch in span's constructor _Extent != __il.size()."); + + return true; +} + +int main(int, char**) { + assert(test()); + + return 0; +} diff --git a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp index d0f4cc795f3e27..a06cecba7b55b7 100644 --- a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp @@ -9,35 +9,136 @@ // <span> -#include <span> +// constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il); // Since C++26 + +#include <array> #include <cassert> +#include <concepts> #include <cstddef> +#include <initializer_list> +#include <span> +#include <vector> + +#include "test_macros.h" + +#include <print> + +#if TEST_STD_VER >= 26 + +constexpr int kEmptySpanValue = -1; + +template <std::size_t N> +int take_last_element(std::span<const int, N> sp, std::size_t expectedSize) { + static_assert(std::dynamic_extent != sp.extent); + assert(sp.size() == expectedSize); + if (sp.size() == 0) + return kEmptySpanValue; + return sp.at(sp.size() - 1); +} + +int take_last_element(std::span<const int> sp, std::size_t expectedSize) { + static_assert(std::dynamic_extent == sp.extent); + std::println(stderr, "size ----- {}", sp.size()); + assert(sp.size() == expectedSize); + if (sp.size() == 0) + return kEmptySpanValue; + return sp.at(sp.size() - 1); +} + +bool test_span() { + // Static + // { + // int lastElem = take_last_element<0>({{}}, 0); + // assert(lastElem == kEmptySpanValue); + // } + // { + // int lastElem = take_last_element<1>({{1}}, 1); + // assert(lastElem == kEmptySpanValue); + // } + // { + // int lastElem = take_last_element<4>(std::array{1, 2, 3, 9084}, 4); + // assert(lastElem == 9084); + // } + // { + // int lastElem = take_last_element<4>(std::initializer_list<int>{1, 2, 3, 9084}, 4); + // assert(lastElem == 9084); + // } + // std::span<const int, 4>({1, 2, 3, 9084, 5}); + // { + // int lastElem = take_last_element(std::span<const int, 4>({1, 2, 3, 9084}), 4); + // assert(lastElem == 9084); + // } + // Dynamic + // { + // int lastElem = take_last_element({{}}, 1); + // assert(lastElem == kEmptySpanValue); + // } + { + int lastElem = take_last_element({{1, 2, 3, 9084}}, 4); + assert(lastElem == 9084); + } + // { + // int lastElem = take_last_element(std::vector{1, 2, 3, 9084}, 4); + // assert(lastElem == 9084); + // } + { + int lastElem = take_last_element(std::initializer_list<int>{1, 2, 3, 9084}, 4); + assert(lastElem == 9084); + } + { + int lastElem = take_last_element(std::span<const int>({1, 2, 3, 9084}), 4); + assert(lastElem == 9084); + } + + return true; +} + +#endif struct Sink { - constexpr Sink() = default; - constexpr Sink(Sink*) {} + constexpr Sink() = default; + constexpr Sink(Sink*) {} }; -constexpr std::size_t count(std::span<const Sink> sp) { - return sp.size(); -} +constexpr std::size_t count(std::span<const Sink> sp) { return sp.size(); } -template<int N> -constexpr std::size_t countn(std::span<const Sink, N> sp) { - return sp.size(); +template <std::size_t N> +constexpr std::size_t count_n(std::span<const Sink, N> sp) { + return sp.size(); } constexpr bool test() { +#if TEST_STD_VER >= 26 + // Dynamic extent + { Sink a[10]; + + assert(count({a}) == 1); + assert(count({a, a + 10}) == 2); + assert(count({a, a + 1, a + 2}) == 3); + // assert(count_n<3>(std::array{a, a + 1, a + 2}) == 3); + // assert(count_n<3>(std::array{a, a + 1, a + 2, a + 3, a + 4}) == 3); + } +#else + { + Sink a[10]; + assert(count({a}) == 10); - assert(count({a, a+10}) == 10); - assert(countn<10>({a}) == 10); - return true; + assert(count({a, a + 10}) == 10); + assert(count_n<10>({a}) == 10); + } +#endif + + return true; } int main(int, char**) { - test(); - static_assert(test()); + test(); + static_assert(test()); + +#if TEST_STD_VER >= 26 + test_span(); +#endif - return 0; + return 0; } diff --git a/libcxx/test/std/containers/views/views.span/span.cons/iterator_len.verify.cpp b/libcxx/test/std/containers/views/views.span/span.cons/iterator_len.verify.cpp index 3836c97e94c6d6..112057e258be33 100644 --- a/libcxx/test/std/containers/views/views.span/span.cons/iterator_len.verify.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/iterator_len.verify.cpp @@ -13,22 +13,36 @@ // constexpr explicit(Extent != dynamic_extent) span(It first, size_type count); // If Extent is not equal to dynamic_extent, then count shall be equal to Extent. // +// constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il); // Since C++26 #include <span> #include <cstddef> +#include "test_macros.h" + template <class T, std::size_t extent> std::span<T, extent> createImplicitSpan(T* ptr, std::size_t len) { return {ptr, len}; // expected-error {{chosen constructor is explicit in copy-initialization}} } -void f() { +void test() { // explicit constructor necessary int arr[] = {1, 2, 3}; createImplicitSpan<int, 1>(arr, 3); - std::span<int> sp = {0, 0}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} - std::span<int, 2> sp2 = {0, 0}; // expected-error {{no matching constructor for initialization of 'std::span<int, 2>'}} - std::span<const int> csp = {0, 0}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} - std::span<const int, 2> csp2 = {0, 0}; // expected-error {{no matching constructor for initialization of 'std::span<const int, 2>'}} + // expected-error@+1 {{no matching constructor for initialization of 'std::span<int>'}} + std::span<int> sp = {0, 0}; + // expected-error@+1 {{no matching constructor for initialization of 'std::span<int, 2>'}} + std::span<int, 2> sp2 = {0, 0}; +#if TEST_STD_VER >= 26 + // No error in C++26 + std::span<const int> csp = {0, 0}; + // expected-error@+1 {{chosen constructor is explicit in copy-initialization}} + std::span<const int, 2> csp2 = {0, 0}; +#else + // expected-error@+1 {{no matching constructor for initialization of 'std::span<const int>'}} + std::span<const int> csp = {0, 0}; + // expected-error@+1 {{no matching constructor for initialization of 'std::span<const int, 2>'}} + std::span<const int, 2> csp2 = {0, 0}; +#endif } diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index 8ee92909dfa53c..958c34edde0059 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -1093,7 +1093,6 @@ def add_version_header(tc): "name": "__cpp_lib_span_initializer_list", "values": {"c++26": 202311}, # P2447R6 std::span over an initializer list "headers": ["span"], - "unimplemented": True, }, { "name": "__cpp_lib_spanstream", >From 780d8574947590845ebc7fdb8c4097af32b87d09 Mon Sep 17 00:00:00 2001 From: Zingam <zin...@outlook.com> Date: Mon, 15 Jan 2024 12:44:48 +0200 Subject: [PATCH 2/9] WIP: Cleanup --- libcxx/include/span | 5 +- .../initializer_list.assert.pass.cpp | 9 +- .../span.cons/initializer_list.pass.cpp | 83 +------------------ 3 files changed, 3 insertions(+), 94 deletions(-) diff --git a/libcxx/include/span b/libcxx/include/span index 7ce0faa9457099..9e5ef779bcadec 100644 --- a/libcxx/include/span +++ b/libcxx/include/span @@ -233,7 +233,6 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr explicit span(std::initializer_list<value_type> __il) requires is_const_v<element_type> : __data_{__il.begin()} { - // static_assert(false, "constructor (static extent) called"); _LIBCPP_ASSERT_INTERNAL(_Extent == __il.size(), "Size mismatch in span's constructor _Extent != __il.size()."); } # endif @@ -410,9 +409,7 @@ public: # if _LIBCPP_STD_VER >= 26 _LIBCPP_HIDE_FROM_ABI constexpr span(std::initializer_list<value_type> __il) requires is_const_v<element_type> - : __data_{__il.begin()}, __size_{__il.size()} { - // static_assert(false, "constructor (dynamic extent) called"); - } + : __data_{__il.begin()}, __size_{__il.size()} {} # endif constexpr span(const span&) noexcept = default; diff --git a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.assert.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.assert.pass.cpp index ecf3f00e833e51..a078a43d6a6eee 100644 --- a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.assert.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.assert.pass.cpp @@ -17,23 +17,16 @@ // constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il); // Since C++26 #include <cassert> -#include <span> #include <initializer_list> +#include <span> #include "check_assertion.h" -// template <std::size_t N> -// void test_runtime_assertion(std::span<const int, N> sp) { -// static_assert(std::dynamic_extent != sp.extent); -// } - bool test() { TEST_LIBCPP_ASSERT_FAILURE( (std::span<const int, 4>({1, 2, 3, 9084, 5})), "Size mismatch in span's constructor _Extent != __il.size()."); TEST_LIBCPP_ASSERT_FAILURE((std::span<const int, 4>(std::initializer_list<int>{1, 2, 3, 9084, 5})), "Size mismatch in span's constructor _Extent != __il.size()."); - // TEST_LIBCPP_ASSERT_FAILURE((test_runtime_assertion(std::span<const int, 4>({1, 2, 3, 9084, 0}))), - // "Size mismatch in span's constructor _Extent != __il.size()."); return true; } diff --git a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp index a06cecba7b55b7..932b962feacd18 100644 --- a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp @@ -13,88 +13,12 @@ #include <array> #include <cassert> -#include <concepts> #include <cstddef> #include <initializer_list> #include <span> -#include <vector> #include "test_macros.h" -#include <print> - -#if TEST_STD_VER >= 26 - -constexpr int kEmptySpanValue = -1; - -template <std::size_t N> -int take_last_element(std::span<const int, N> sp, std::size_t expectedSize) { - static_assert(std::dynamic_extent != sp.extent); - assert(sp.size() == expectedSize); - if (sp.size() == 0) - return kEmptySpanValue; - return sp.at(sp.size() - 1); -} - -int take_last_element(std::span<const int> sp, std::size_t expectedSize) { - static_assert(std::dynamic_extent == sp.extent); - std::println(stderr, "size ----- {}", sp.size()); - assert(sp.size() == expectedSize); - if (sp.size() == 0) - return kEmptySpanValue; - return sp.at(sp.size() - 1); -} - -bool test_span() { - // Static - // { - // int lastElem = take_last_element<0>({{}}, 0); - // assert(lastElem == kEmptySpanValue); - // } - // { - // int lastElem = take_last_element<1>({{1}}, 1); - // assert(lastElem == kEmptySpanValue); - // } - // { - // int lastElem = take_last_element<4>(std::array{1, 2, 3, 9084}, 4); - // assert(lastElem == 9084); - // } - // { - // int lastElem = take_last_element<4>(std::initializer_list<int>{1, 2, 3, 9084}, 4); - // assert(lastElem == 9084); - // } - // std::span<const int, 4>({1, 2, 3, 9084, 5}); - // { - // int lastElem = take_last_element(std::span<const int, 4>({1, 2, 3, 9084}), 4); - // assert(lastElem == 9084); - // } - // Dynamic - // { - // int lastElem = take_last_element({{}}, 1); - // assert(lastElem == kEmptySpanValue); - // } - { - int lastElem = take_last_element({{1, 2, 3, 9084}}, 4); - assert(lastElem == 9084); - } - // { - // int lastElem = take_last_element(std::vector{1, 2, 3, 9084}, 4); - // assert(lastElem == 9084); - // } - { - int lastElem = take_last_element(std::initializer_list<int>{1, 2, 3, 9084}, 4); - assert(lastElem == 9084); - } - { - int lastElem = take_last_element(std::span<const int>({1, 2, 3, 9084}), 4); - assert(lastElem == 9084); - } - - return true; -} - -#endif - struct Sink { constexpr Sink() = default; constexpr Sink(Sink*) {} @@ -116,8 +40,7 @@ constexpr bool test() { assert(count({a}) == 1); assert(count({a, a + 10}) == 2); assert(count({a, a + 1, a + 2}) == 3); - // assert(count_n<3>(std::array{a, a + 1, a + 2}) == 3); - // assert(count_n<3>(std::array{a, a + 1, a + 2, a + 3, a + 4}) == 3); + assert(count(std::initializer_list<Sink>{a[0], a[1], a[2], a[3]}) == 4); } #else { @@ -136,9 +59,5 @@ int main(int, char**) { test(); static_assert(test()); -#if TEST_STD_VER >= 26 - test_span(); -#endif - return 0; } >From cbe6fa053879200e497c22455f0f09915f605c27 Mon Sep 17 00:00:00 2001 From: Zingam <zin...@outlook.com> Date: Mon, 15 Jan 2024 12:48:20 +0200 Subject: [PATCH 3/9] Added generated version files --- libcxx/docs/FeatureTestMacroTable.rst | 2 +- libcxx/include/version | 2 +- .../span.version.compile.pass.cpp | 16 +++++----------- .../version.version.compile.pass.cpp | 16 +++++----------- 4 files changed, 12 insertions(+), 24 deletions(-) diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 893a3b13ca06e0..82e51d4e7eb53d 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -438,7 +438,7 @@ Status --------------------------------------------------- ----------------- ``__cpp_lib_span_at`` ``202311L`` --------------------------------------------------- ----------------- - ``__cpp_lib_span_initializer_list`` *unimplemented* + ``__cpp_lib_span_initializer_list`` ``202311L`` --------------------------------------------------- ----------------- ``__cpp_lib_sstream_from_string_view`` *unimplemented* --------------------------------------------------- ----------------- diff --git a/libcxx/include/version b/libcxx/include/version index c96647894dce63..7b2f487fe70205 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -507,7 +507,7 @@ __cpp_lib_within_lifetime 202306L <type_traits> // # define __cpp_lib_saturation_arithmetic 202311L // # define __cpp_lib_smart_ptr_owner_equality 202306L # define __cpp_lib_span_at 202311L -// # define __cpp_lib_span_initializer_list 202311L +# define __cpp_lib_span_initializer_list 202311L // # define __cpp_lib_sstream_from_string_view 202306L // # define __cpp_lib_submdspan 202306L // # define __cpp_lib_text_encoding 202306L diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/span.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/span.version.compile.pass.cpp index dbbbaf4ec7c228..e1694308f12a7b 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/span.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/span.version.compile.pass.cpp @@ -116,17 +116,11 @@ # error "__cpp_lib_span_at should have the value 202311L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_span_initializer_list -# error "__cpp_lib_span_initializer_list should be defined in c++26" -# endif -# if __cpp_lib_span_initializer_list != 202311L -# error "__cpp_lib_span_initializer_list should have the value 202311L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_span_initializer_list -# error "__cpp_lib_span_initializer_list should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_span_initializer_list +# error "__cpp_lib_span_initializer_list should be defined in c++26" +# endif +# if __cpp_lib_span_initializer_list != 202311L +# error "__cpp_lib_span_initializer_list should have the value 202311L in c++26" # endif #endif // TEST_STD_VER > 23 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index d5a0839b30f824..fa188533446b47 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -7294,17 +7294,11 @@ # error "__cpp_lib_span_at should have the value 202311L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_span_initializer_list -# error "__cpp_lib_span_initializer_list should be defined in c++26" -# endif -# if __cpp_lib_span_initializer_list != 202311L -# error "__cpp_lib_span_initializer_list should have the value 202311L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_span_initializer_list -# error "__cpp_lib_span_initializer_list should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_span_initializer_list +# error "__cpp_lib_span_initializer_list should be defined in c++26" +# endif +# if __cpp_lib_span_initializer_list != 202311L +# error "__cpp_lib_span_initializer_list should have the value 202311L in c++26" # endif # if !defined(_LIBCPP_VERSION) >From de98ad0c99cedd21760b05782bbaf85e96a052c4 Mon Sep 17 00:00:00 2001 From: Zingam <zin...@outlook.com> Date: Mon, 15 Jan 2024 13:26:39 +0200 Subject: [PATCH 4/9] Added SFINAE --- .../span.cons/initializer_list.pass.cpp | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp index 932b962feacd18..66f4de5eb3ab4e 100644 --- a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp @@ -16,9 +16,38 @@ #include <cstddef> #include <initializer_list> #include <span> +#include <type_traits> #include "test_macros.h" +#if TEST_STD_VER >= 26 + +// SFINAE + +template <typename T> +concept ConstElementType = std::is_const_v<typename T::element_type>; + +static_assert(ConstElementType<std::span<const int>>); +static_assert(!ConstElementType<std::span<int>>); +static_assert(ConstElementType<std::span<const int, 94>>); +static_assert(!ConstElementType<std::span<int, 94>>); + +// template <typename T, typename I> +// concept HasInitializerListCtr = requires(I il) { std::span<T>{il}; }; + +// static_assert(HasInitializerListCtr<const int, std::initializer_list<const int>>); +// static_assert(!HasInitializerListCtr<int, std::initializer_list<int>>); + +template <typename I, typename T, std::size_t... N> +concept HasInitializerListCtr = requires(I il) { std::span<T, N...>{il}; }; + +static_assert(HasInitializerListCtr<std::initializer_list<const int>, const int>); +static_assert(!HasInitializerListCtr<std::initializer_list<int>, int>); +static_assert(HasInitializerListCtr<std::initializer_list<const int>, const int, 94>); +static_assert(!HasInitializerListCtr<std::initializer_list<int>, int, 94>); + +#endif + struct Sink { constexpr Sink() = default; constexpr Sink(Sink*) {} >From 7add5b4fe4d1528651b35d37cd4797412bbc3f53 Mon Sep 17 00:00:00 2001 From: Zingam <zin...@outlook.com> Date: Mon, 15 Jan 2024 15:15:55 +0200 Subject: [PATCH 5/9] Cleanup --- .../views/views.span/span.cons/initializer_list.pass.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp index 66f4de5eb3ab4e..174a45ee6129c6 100644 --- a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp @@ -11,7 +11,6 @@ // constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il); // Since C++26 -#include <array> #include <cassert> #include <cstddef> #include <initializer_list> @@ -32,12 +31,6 @@ static_assert(!ConstElementType<std::span<int>>); static_assert(ConstElementType<std::span<const int, 94>>); static_assert(!ConstElementType<std::span<int, 94>>); -// template <typename T, typename I> -// concept HasInitializerListCtr = requires(I il) { std::span<T>{il}; }; - -// static_assert(HasInitializerListCtr<const int, std::initializer_list<const int>>); -// static_assert(!HasInitializerListCtr<int, std::initializer_list<int>>); - template <typename I, typename T, std::size_t... N> concept HasInitializerListCtr = requires(I il) { std::span<T, N...>{il}; }; >From 801cb187d9c9bfd7538eaa28cc958343148f0f0d Mon Sep 17 00:00:00 2001 From: Zingam <zin...@outlook.com> Date: Mon, 15 Jan 2024 15:21:06 +0200 Subject: [PATCH 6/9] Try to fix CI --- libcxx/docs/Status/Cxx2cPapers.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 2a7ee46816e9d9..e48e2e94b30582 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -34,7 +34,7 @@ "`P2918R2 <https://wg21.link/P2918R2>`__","LWG","Runtime format strings II","Kona November 2023","|Complete|","18.0","|format|" "`P2909R4 <https://wg21.link/P2909R4>`__","LWG","Fix formatting of code units as integers (Dude, where’s my ``char``?)","Kona November 2023","|Complete|","18.0","|format| |DR|" "`P0952R2 <https://wg21.link/P0952R2>`__","LWG","A new specification for ``std::generate_canonical``","Kona November 2023","","","" -"`P2447R6 <https://wg21.link/P2447R6>`__","LWG","``std::span`` over an initializer list","Kona November 2023","|Complete","18.0","" +"`P2447R6 <https://wg21.link/P2447R6>`__","LWG","``std::span`` over an initializer list","Kona November 2023","|Complete|","18.0","" "`P2821R5 <https://wg21.link/P2821R5>`__","LWG","``span.at()``","Kona November 2023","|Complete|","18.0","" "`P2868R3 <https://wg21.link/P2868R3>`__","LWG","Remove Deprecated ``std::allocator`` Typedef From C++26","Kona November 2023","","","" "`P2870R3 <https://wg21.link/P2870R3>`__","LWG","Remove ``basic_string::reserve()`` From C++26","Kona November 2023","|Complete|","18.0","" >From 2383ac32f84e5592ab2454f906fbd8e7b5bc13a0 Mon Sep 17 00:00:00 2001 From: Zingam <zin...@outlook.com> Date: Mon, 15 Jan 2024 15:22:35 +0200 Subject: [PATCH 7/9] Try to fix CI --- .../std/containers/views/views.span/span.cons/array.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/containers/views/views.span/span.cons/array.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/array.pass.cpp index b01fdda84789ce..c02f42400b6e1e 100644 --- a/libcxx/test/std/containers/views/views.span/span.cons/array.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/array.pass.cpp @@ -95,7 +95,7 @@ constexpr bool testSpan() std::span<const int> s5 = {{1,2}}; #if TEST_STD_VER >= 26 - std::span<const int, 2> s6({1,2}); + std::span<const int, 2> s6({1, 2}); #else std::span<const int, 2> s6 = {{1,2}}; #endif >From 6c89879ca378b3277beb05b3c9dd96986528cb1d Mon Sep 17 00:00:00 2001 From: Zingam <zin...@outlook.com> Date: Mon, 15 Jan 2024 22:47:31 +0200 Subject: [PATCH 8/9] WIP: Addressed some comments --- libcxx/include/span | 3 ++- .../views.span/span.cons/initializer_list.pass.cpp | 12 ++++++++++++ .../views.span/span.cons/iterator_len.verify.cpp | 7 +------ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/libcxx/include/span b/libcxx/include/span index 9e5ef779bcadec..32364b4270be9e 100644 --- a/libcxx/include/span +++ b/libcxx/include/span @@ -233,7 +233,8 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr explicit span(std::initializer_list<value_type> __il) requires is_const_v<element_type> : __data_{__il.begin()} { - _LIBCPP_ASSERT_INTERNAL(_Extent == __il.size(), "Size mismatch in span's constructor _Extent != __il.size()."); + _LIBCPP_ASSERT_VALID_INPUT_RANGE( + _Extent == __il.size(), "Size mismatch in span's constructor _Extent != __il.size()."); } # endif diff --git a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp index 174a45ee6129c6..b1453aae649792 100644 --- a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp @@ -17,6 +17,7 @@ #include <span> #include <type_traits> +#include "test_convertible.h" #include "test_macros.h" #if TEST_STD_VER >= 26 @@ -31,6 +32,8 @@ static_assert(!ConstElementType<std::span<int>>); static_assert(ConstElementType<std::span<const int, 94>>); static_assert(!ConstElementType<std::span<int, 94>>); +// Constructor constraings + template <typename I, typename T, std::size_t... N> concept HasInitializerListCtr = requires(I il) { std::span<T, N...>{il}; }; @@ -39,6 +42,15 @@ static_assert(!HasInitializerListCtr<std::initializer_list<int>, int>); static_assert(HasInitializerListCtr<std::initializer_list<const int>, const int, 94>); static_assert(!HasInitializerListCtr<std::initializer_list<int>, int, 94>); +// Constructor conditionally explicit + +static_assert(!test_convertible<std::span<const int, 28>, std::initializer_list<int>>(), + "This constructor must be explicit"); +static_assert(std::is_constructible_v<std::span<const int, 28>, std::initializer_list<int>>); +static_assert(test_convertible<std::span<const int>, std::initializer_list<int>>(), + "This constructor must not be explicit"); +static_assert(std::is_constructible_v<std::span<const int>, std::initializer_list<int>>); + #endif struct Sink { diff --git a/libcxx/test/std/containers/views/views.span/span.cons/iterator_len.verify.cpp b/libcxx/test/std/containers/views/views.span/span.cons/iterator_len.verify.cpp index 112057e258be33..176ca200792695 100644 --- a/libcxx/test/std/containers/views/views.span/span.cons/iterator_len.verify.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/iterator_len.verify.cpp @@ -34,12 +34,7 @@ void test() { std::span<int> sp = {0, 0}; // expected-error@+1 {{no matching constructor for initialization of 'std::span<int, 2>'}} std::span<int, 2> sp2 = {0, 0}; -#if TEST_STD_VER >= 26 - // No error in C++26 - std::span<const int> csp = {0, 0}; - // expected-error@+1 {{chosen constructor is explicit in copy-initialization}} - std::span<const int, 2> csp2 = {0, 0}; -#else +#if TEST_STD_VER < 26 // expected-error@+1 {{no matching constructor for initialization of 'std::span<const int>'}} std::span<const int> csp = {0, 0}; // expected-error@+1 {{no matching constructor for initialization of 'std::span<const int, 2>'}} >From 2172198b2204f2e89bdc318d8a78d2d789ce7446 Mon Sep 17 00:00:00 2001 From: Zingam <zin...@outlook.com> Date: Mon, 15 Jan 2024 23:52:49 +0200 Subject: [PATCH 9/9] Addressed comments --- .../span.cons/initializer_list.pass.cpp | 43 ++++++++++++++++- .../span.cons/initializer_list.verify.cpp | 48 +++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 libcxx/test/std/containers/views/views.span/span.cons/initializer_list.verify.cpp diff --git a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp index b1453aae649792..74a5094f61261d 100644 --- a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp @@ -5,12 +5,14 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + // UNSUPPORTED: c++03, c++11, c++14, c++17 // <span> // constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il); // Since C++26 +#include <any> #include <cassert> #include <cstddef> #include <initializer_list> @@ -89,9 +91,48 @@ constexpr bool test() { return true; } +// Test P2447R4 "Annex C examples" + +constexpr int three(std::span<void* const> sp) { return sp.size(); } + +constexpr int four(std::span<const std::any> sp) { return sp.size(); } + +bool test_P2447R4_annex_c_examples() { + // 1. Overload resolution is affected + // --> tested in "initializer_list.verify.cpp" + + // 2. The `initializer_list` ctor has high precedence + // --> tested in "initializer_list.verify.cpp" + + // 3. Implicit two-argument construction with a highly convertible value_type +#if TEST_STD_VER >= 26 + { + void* a[10]; + assert(three({a, 0}) == 2); + } + { + std::any a[10]; + assert(four({a, a + 10}) == 2); + } +#else + { + void* a[10]; + assert(three({a, 0}) == 0); + } + { + std::any a[10]; + assert(four({a, a + 10}) == 10); + } +#endif + + return true; +} + int main(int, char**) { - test(); + assert(test()); static_assert(test()); + assert(test_P2447R4_annex_c_examples()); + return 0; } diff --git a/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.verify.cpp b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.verify.cpp new file mode 100644 index 00000000000000..93bcd0551cdb05 --- /dev/null +++ b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.verify.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// <span> + +// constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il); // Since C++26 + +#include <span> +#include <utility> + +#include "test_macros.h" + +// Test P2447R4 "Annex C examples" + +void one(std::pair<int, int>); +void one(std::span<const int>); + +void two(std::span<const int, 2>); + +void test_P2447R4_annex_c_examples() { + // 1. Overload resolution is affected +#if TEST_STD_VER >= 26 + // expected-error@+1 {{call to 'one' is ambiguous}} + one({1, 2}); +#else + // expected-no-diagnostics + one({1, 2}); +#endif + +// 2. The `initializer_list` ctor has high precedence +#if TEST_STD_VER >= 26 + // expected-error@+1 {{chosen constructor is explicit in copy-initialization}} + two({{1, 2}}); +#else + // expected-no-diagnostics + two({{1, 2}}); +#endif + + // 3. Implicit two-argument construction with a highly convertible value_type + // --> tested in "initializer_list.pass.cpp" +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits