Hello, On 20/12/2024 18:05, Jonathan Wakely wrote:
So I think I'll just finish testing it like that, as one test, and push that.
OK, thanks.But in fact, I've realized that it doesn't need to be run at all? There's nothing that happens at runtime. I've therefore made the test just a compile time one.
Thanks, -- Giuseppe D'Angelo
From 9036ca04aaf07557c7dc14d995d2a8d4b41d5289 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo <giuseppe.dang...@kdab.com> Date: Tue, 3 Dec 2024 16:56:45 +0100 Subject: [PATCH] libstdc++: add initializer_list constructor to std::span (P2447R6) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit implements P2447R6. The code is straightforward (just one extra constructor, with constraints and conditional explicit). I decided to suppress -Winit-list-lifetime because otherwise it would give too many false positives. The new constructor is meant to be used as a parameter-passing interface (this is a design choice, see P2447R6/ยง2) and, as such, the initializer_list won't dangle despite GCC's warnings. The new constructor isn't 100% backwards compatible. A couple of examples are included in Annex C, but I have also lifted some more from R4. A new test checks for the old and the new behaviors. libstdc++-v3/ChangeLog: * include/bits/version.def: Added the new feature-testing macro. * include/bits/version.h (defined): Regenerated. * include/std/span: Added constructor from initializer_list. * testsuite/23_containers/span/init_list_cons.cc: New test. * testsuite/23_containers/span/init_list_cons_neg.cc: New test. Signed-off-by: Giuseppe D'Angelo <giuseppe.dang...@kdab.com> --- libstdc++-v3/include/bits/version.def | 8 +++ libstdc++-v3/include/bits/version.h | 10 +++ libstdc++-v3/include/std/span | 17 +++++ .../23_containers/span/init_list_cons.cc | 65 +++++++++++++++++++ .../23_containers/span/init_list_cons_neg.cc | 36 ++++++++++ 5 files changed, 136 insertions(+) create mode 100644 libstdc++-v3/testsuite/23_containers/span/init_list_cons.cc create mode 100644 libstdc++-v3/testsuite/23_containers/span/init_list_cons_neg.cc diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 3b31cff5194..62b8252e02d 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1869,6 +1869,14 @@ ftms = { }; }; +ftms = { + name = span_initializer_list; + values = { + v = 202311; + cxxmin = 26; + }; +}; + ftms = { name = text_encoding; values = { diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index ef27ae5e4fa..16cdae920a1 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -2075,6 +2075,16 @@ #endif /* !defined(__cpp_lib_saturation_arithmetic) && defined(__glibcxx_want_saturation_arithmetic) */ #undef __glibcxx_want_saturation_arithmetic +#if !defined(__cpp_lib_span_initializer_list) +# if (__cplusplus > 202302L) +# define __glibcxx_span_initializer_list 202311L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_span_initializer_list) +# define __cpp_lib_span_initializer_list 202311L +# endif +# endif +#endif /* !defined(__cpp_lib_span_initializer_list) && defined(__glibcxx_want_span_initializer_list) */ +#undef __glibcxx_want_span_initializer_list + #if !defined(__cpp_lib_text_encoding) # if (__cplusplus > 202302L) && _GLIBCXX_HOSTED && (_GLIBCXX_USE_NL_LANGINFO_L) # define __glibcxx_text_encoding 202306L diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index e8043c02c9a..c8aa5c02635 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -39,6 +39,7 @@ #endif #define __glibcxx_want_span +#define __glibcxx_want_span_initializer_list #include <bits/version.h> #ifdef __cpp_lib_span // C++ >= 20 && concepts @@ -46,6 +47,9 @@ #include <cstddef> #include <bits/stl_iterator.h> #include <bits/ranges_base.h> +#ifdef __cpp_lib_span_initializer_list +# include <initializer_list> +#endif namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -228,6 +232,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _M_ptr(ranges::data(__range)), _M_extent(ranges::size(__range)) { } +#if __cpp_lib_span_initializer_list >= 202311L // >= C++26 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Winit-list-lifetime" + constexpr + explicit(extent != dynamic_extent) + span(initializer_list<value_type> __il) + requires (is_const_v<_Type>) + : _M_ptr(__il.begin()), _M_extent(__il.size()) + { + } +#pragma GCC diagnostic pop +#endif + constexpr span(const span&) noexcept = default; diff --git a/libstdc++-v3/testsuite/23_containers/span/init_list_cons.cc b/libstdc++-v3/testsuite/23_containers/span/init_list_cons.cc new file mode 100644 index 00000000000..1dc30ab1a50 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/span/init_list_cons.cc @@ -0,0 +1,65 @@ +// { dg-do compile { target c++26 } } + +#include <span> +#include <type_traits> + +#if !defined(__cpp_lib_span_initializer_list) +# error "__cpp_lib_span_initializer_list should be defined" +#elif __cpp_lib_span_initializer_list < 202311L +# error "Wrong value for __cpp_lib_span_initializer_list (should be >= 202311L)" +#endif + +// Check the constraint on the initializer_list constructor +static_assert( std::is_const_v<std::span<const int>::element_type>); +static_assert(!std::is_const_v<std::span< int>::element_type>); + +static_assert( std::is_constructible_v<std::span<const int >, std::initializer_list< int>>); +static_assert( std::is_constructible_v<std::span<const int >, std::initializer_list<const int>>); +static_assert( std::is_constructible_v<std::span<const int, 42>, std::initializer_list< int>>); +static_assert( std::is_constructible_v<std::span<const int, 42>, std::initializer_list<const int>>); +static_assert(!std::is_constructible_v<std::span< int >, std::initializer_list< int>>); +static_assert(!std::is_constructible_v<std::span< int >, std::initializer_list<const int>>); +static_assert(!std::is_constructible_v<std::span< int, 42>, std::initializer_list< int>>); +static_assert(!std::is_constructible_v<std::span< int, 42>, std::initializer_list<const int>>); + +// Check the explicit-ness on the initializer_list constructor +static_assert( std::is_convertible_v<std::initializer_list< int>, std::span<const int >>); +static_assert( std::is_convertible_v<std::initializer_list<const int>, std::span<const int >>); +static_assert(!std::is_convertible_v<std::initializer_list< int>, std::span<const int, 42>>); +static_assert(!std::is_convertible_v<std::initializer_list<const int>, std::span<const int, 42>>); +static_assert(!std::is_convertible_v<std::initializer_list< int>, std::span< int >>); +static_assert(!std::is_convertible_v<std::initializer_list<const int>, std::span< int >>); +static_assert(!std::is_convertible_v<std::initializer_list< int>, std::span< int, 42>>); +static_assert(!std::is_convertible_v<std::initializer_list<const int>, std::span< int, 42>>); + +constexpr size_t fun1(std::span<const int> s) +{ + return s.size(); +} + +static_assert(fun1({}) == 0); +static_assert(fun1({1, 2, 3}) == 3); +static_assert(fun1(std::initializer_list<int>{1, 2, 3}) == 3); + +// Stress-test array->pointer decays +struct decayer { + constexpr decayer() = default; + constexpr decayer(decayer *) {} +}; + +constexpr size_t fun2(std::span<const decayer> s) +{ + return s.size(); +} + +void test01() +{ + int intArray[42]; + static_assert(fun1(intArray) == 42); + + decayer decArray[42]; + static_assert(fun2(decArray) == 42); + static_assert(fun2({decArray}) == 1); // decayer[] -> decayer* -> decayer(decayer*) -> init_list<decayer> of 1 element + static_assert(fun2({decArray, decArray + 42}) == 2); // does not select span(iterator, iterator) + static_assert(fun2({decArray, decArray, decArray}) == 3); +} diff --git a/libstdc++-v3/testsuite/23_containers/span/init_list_cons_neg.cc b/libstdc++-v3/testsuite/23_containers/span/init_list_cons_neg.cc new file mode 100644 index 00000000000..beae64c3c04 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/span/init_list_cons_neg.cc @@ -0,0 +1,36 @@ +// { dg-do compile { target c++20 } } + +#include <span> +#include <utility> + +#include <testsuite_hooks.h> + +struct Any +{ + constexpr Any() { } + template<typename T> constexpr Any(T) { } +}; + +// Examples from P2447R4 +void one(std::pair<int, int>) {} +void one(std::span<const int>) {} +void two(std::span<const int, 2>) {} +constexpr std::size_t three(std::span<void * const> v) { return v.size(); } +constexpr std::size_t four(std::span<const Any> v) { return v.size(); } + +void *array3[10]; +Any array4[10]; + +int main() +{ + one({1, 2}); // { dg-error "call of overloaded" "should be ambiguous with the one(std::pair) overload" { target c++26 } } + two({{1, 2}}); // { dg-error "would use explicit constructor" "should prefer the initializer_list constructor, which is explicit" { target c++26 } } + +#if __cpp_lib_span_initializer_list + static_assert(three({array3, 0}) == 2); + static_assert(four({array4, array4 + 10}) == 2); +#else + static_assert(three({array3, 0}) == 0); + static_assert(four({array4, array4 + 10}) == 10); +#endif +} -- 2.34.1
smime.p7s
Description: S/MIME Cryptographic Signature