[libcxx-commits] [libcxx] [libc++][span] P2447R4: `std::span` over an initializer list (PR #78157)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jan 15 05:17:41 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Hristo Hristov (H-G-Hristov)
<details>
<summary>Changes</summary>
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
---
Full diff: https://github.com/llvm/llvm-project/pull/78157.diff
12 Files Affected:
- (modified) libcxx/docs/FeatureTestMacroTable.rst (+1-1)
- (modified) libcxx/docs/ReleaseNotes/18.rst (+1)
- (modified) libcxx/docs/Status/Cxx2cPapers.csv (+1-1)
- (modified) libcxx/include/span (+15)
- (modified) libcxx/include/version (+1-1)
- (modified) libcxx/test/std/containers/views/views.span/span.cons/array.pass.cpp (+4)
- (added) libcxx/test/std/containers/views/views.span/span.cons/initializer_list.assert.pass.cpp (+38)
- (modified) libcxx/test/std/containers/views/views.span/span.cons/initializer_list.pass.cpp (+57-15)
- (modified) libcxx/test/std/containers/views/views.span/span.cons/iterator_len.verify.cpp (+19-5)
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/span.version.compile.pass.cpp (+5-11)
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp (+5-11)
- (modified) libcxx/utils/generate_feature_test_macro_components.py (-1)
``````````diff
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/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..9e5ef779bcadec 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,14 @@ 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()} {
+ _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 +406,12 @@ 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()} {}
+# endif
+
constexpr span(const span&) noexcept = default;
constexpr span& operator=(const span&) noexcept = default;
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/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..a078a43d6a6eee
--- /dev/null
+++ b/libcxx/test/std/containers/views/views.span/span.cons/initializer_list.assert.pass.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <initializer_list>
+#include <span>
+
+#include "check_assertion.h"
+
+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().");
+
+ 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..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
@@ -9,35 +9,77 @@
// <span>
-#include <span>
+// constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il); // Since C++26
+
#include <cassert>
#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 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*) {}
+ 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(std::initializer_list<Sink>{a[0], a[1], a[2], a[3]}) == 4);
+ }
+#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());
- 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 at +1 {{no matching constructor for initialization of 'std::span<int>'}}
+ std::span<int> sp = {0, 0};
+ // expected-error at +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 at +1 {{chosen constructor is explicit in copy-initialization}}
+ std::span<const int, 2> csp2 = {0, 0};
+#else
+ // expected-error at +1 {{no matching constructor for initialization of 'std::span<const int>'}}
+ std::span<const int> csp = {0, 0};
+ // expected-error at +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/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)
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",
``````````
</details>
https://github.com/llvm/llvm-project/pull/78157
More information about the libcxx-commits
mailing list