[gcc r16-3650] libstdc++: Adjust span/mdspan CTAD for P2781R9.

Tomasz Kaminski tkaminsk@gcc.gnu.org
Mon Sep 8 07:41:27 GMT 2025


https://gcc.gnu.org/g:71711f8ac3af615fec197e4eb71d0bee8ef44a23

commit r16-3650-g71711f8ac3af615fec197e4eb71d0bee8ef44a23
Author: Luc Grosheintz <luc.grosheintz@gmail.com>
Date:   Thu Sep 4 14:20:29 2025 +0200

    libstdc++: Adjust span/mdspan CTAD for P2781R9.
    
    A usecase for P2781R9 is more ergonomic creation of span and mdspan with
    mixed static and dynamic extents, e.g.:
    
        span(ptr, cw<3>)
        extents(cw<3>, 5, cw<7>)
        mdspan(ptr, cw<3>, 5, cw<7>)
    
    should be deduced as:
        span<..., 3>
        extents<..., 3, dyn, 7>
        mdspan<..., extents<..., 3, dyn, 7>>
    
    The change required is to strip cv-qualifiers and references from
    `_Tp::value`, because of:
    
        template<_CwFixedValue _X, typename>
          struct constant_wrapper : _CwOperators
          {
            static constexpr const auto& value = _X._M_data;
    
    libstdc++-v3/ChangeLog:
    
            * include/std/span (__integral_constant_like): Allow the member
            `value` of a constant wrapping type to be a const reference of
            an integer.
            * testsuite/23_containers/mdspan/extents/misc.cc: Add test for
            cw and constant_wrapper.
            * testsuite/23_containers/mdspan/mdspan.cc: Ditto.
            * testsuite/23_containers/span/deduction.cc: Ditto.
    
    Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
    Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com>
    Signed-off-by: Luc Grosheintz <luc.grosheintz@gmail.com>

Diff:
---
 libstdc++-v3/include/std/span                      |  3 ++-
 .../testsuite/23_containers/mdspan/extents/misc.cc | 22 +++++++++++++++------
 .../testsuite/23_containers/mdspan/mdspan.cc       | 23 +++++++++++++++-------
 .../testsuite/23_containers/span/deduction.cc      | 20 ++++++++++++++++++-
 4 files changed, 53 insertions(+), 15 deletions(-)

diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span
index 44f9b36a7efe..f9aa3c77e8e1 100644
--- a/libstdc++-v3/include/std/span
+++ b/libstdc++-v3/include/std/span
@@ -480,7 +480,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   namespace __detail
   {
     template<typename _Tp>
-      concept __integral_constant_like = is_integral_v<decltype(_Tp::value)>
+      concept __integral_constant_like =
+	is_integral_v<remove_cvref_t<decltype(_Tp::value)>>
 	&& !is_same_v<bool, remove_const_t<decltype(_Tp::value)>>
 	&& convertible_to<_Tp, decltype(_Tp::value)>
 	&& equality_comparable_with<_Tp, decltype(_Tp::value)>
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
index 8a43a682004d..94086653a745 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
@@ -98,7 +98,7 @@ test_deduction(Extents... exts)
 }
 
 constexpr bool
-test_integral_constant_deduction()
+test_deduction_from_constant()
 {
   auto verify = [](auto actual, auto expected)
     {
@@ -106,13 +106,23 @@ test_integral_constant_deduction()
       VERIFY(actual == expected);
     };
 
-  constexpr auto c1 = std::integral_constant<size_t, 1>{};
-  constexpr auto c2 = std::integral_constant<int, 2>{};
+  constexpr auto i1 = std::integral_constant<size_t, 1>{};
+  constexpr auto i2 = std::integral_constant<int, 2>{};
 
   verify(std::extents(1), std::extents<size_t, dyn>{1});
-  verify(std::extents(c1), std::extents<size_t, 1>{});
+  verify(std::extents(i1), std::extents<size_t, 1>{});
+  verify(std::extents(i2), std::extents<size_t, 2>{});
+  verify(std::extents(std::true_type{}, 2), std::dextents<size_t, 2>{1, 2});
+  verify(std::extents(std::false_type{}, 2), std::dextents<size_t, 2>{0, 2});
+
+#if __glibcxx_constant_wrapper
+  constexpr auto c2 = std::constant_wrapper<2>{};
+  verify(std::extents(c2), std::extents<size_t, 2>{});
+  verify(std::extents(1, c2), std::extents<size_t, dyn, 2>{1});
   verify(std::extents(c2), std::extents<size_t, 2>{});
-  verify(std::extents(c1, 2), std::extents<size_t, 1, dyn>{2});
+  verify(std::extents(1, c2), std::extents<size_t, dyn, 2>{1});
+  verify(std::extents(std::cw<true>, c2), std::extents<size_t, 1, 2>{});
+#endif
   return true;
 }
 
@@ -123,7 +133,7 @@ test_deduction_all()
   test_deduction<1>(1);
   test_deduction<2>(1.0, 2.0f);
   test_deduction<3>(int(1), short(2), size_t(3));
-  test_integral_constant_deduction();
+  test_deduction_from_constant();
   return true;
 }
 
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
index bdfc6ebcf561..ca100b4f314a 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
@@ -280,7 +280,7 @@ test_from_pointer_and_shape()
 }
 
 constexpr bool
-test_from_pointer_and_integral_constant()
+test_from_pointer_and_constant()
 {
   std::array<double, 6> buffer{};
   double * ptr = buffer.data();
@@ -292,12 +292,21 @@ test_from_pointer_and_integral_constant()
       VERIFY(actual.extents() == expected.extents());
     };
 
-  auto c3 = std::integral_constant<int, 3>{};
-  auto c6 = std::integral_constant<int, 6>{};
+  auto i3 = std::integral_constant<int, 3>{};
+  auto i6 = std::integral_constant<int, 6>{};
 
   verify(std::mdspan(ptr, 6), std::extents(6));
-  verify(std::mdspan(ptr, c6), std::extents(c6));
-  verify(std::mdspan(ptr, 2, c3), std::extents(2, c3));
+  verify(std::mdspan(ptr, i6), std::extents(i6));
+  verify(std::mdspan(ptr, 2, i3), std::extents(2, i3));
+  verify(std::mdspan(ptr, std::true_type{}, i3), std::extents(1, i3));
+
+#if __glibcxx_constant_wrapper
+  auto c3 = std::constant_wrapper<3>{};
+  verify(std::mdspan(ptr, 2, c3), std::extents(2, i3));
+  verify(std::mdspan(ptr, 2, std::cw<3>), std::extents(2, i3));
+  verify(std::mdspan(ptr, std::cw<true>, std::cw<3>),
+	 std::extents(std::cw<1>, i3));
+#endif
   return true;
 }
 
@@ -729,8 +738,8 @@ main()
   test_from_pointer_and_shape();
   static_assert(test_from_pointer_and_shape());
 
-  test_from_pointer_and_integral_constant();
-  static_assert(test_from_pointer_and_integral_constant());
+  test_from_pointer_and_constant();
+  static_assert(test_from_pointer_and_constant());
 
   test_from_extents();
   static_assert(test_from_extents());
diff --git a/libstdc++-v3/testsuite/23_containers/span/deduction.cc b/libstdc++-v3/testsuite/23_containers/span/deduction.cc
index c66db90222e6..e958ad5d6db0 100644
--- a/libstdc++-v3/testsuite/23_containers/span/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/span/deduction.cc
@@ -82,5 +82,23 @@ test01()
   static_assert( is_dynamic_span<int>(s12) );
 
   std::span s13(a.data(), std::integral_constant<size_t, 3>{});
-  static_assert( is_static_span<long, 3>(s13));
+  static_assert( is_static_span<long, 3>(s13) );
+
+  std::span s14(a.data(), true);
+  static_assert( is_dynamic_span<long>(s14) );
+
+  std::span s15(a.data(), std::true_type{});
+  static_assert( is_dynamic_span<long>(s15) );
+
+#if __glibcxx_constant_wrapper
+  auto c5 = std::constant_wrapper<5>{};
+  std::span s16(a.data(), c5);
+  static_assert( is_static_span<long, 5>(s16) );
+
+  std::span s17(a.data(), std::cw<4>);
+  static_assert( is_static_span<long, 4>(s17) );
+
+  std::span s18(a.data(), std::cw<true>);
+  static_assert( is_static_span<long, 1>(s18) );
+#endif
 }


More information about the Libstdc++-cvs mailing list