https://gcc.gnu.org/g:9c600a7e6cc588d2ee79d764cbf69ad677b1bac5

commit r16-2106-g9c600a7e6cc588d2ee79d764cbf69ad677b1bac5
Author: Luc Grosheintz <luc.groshei...@gmail.com>
Date:   Tue Jul 8 11:49:21 2025 +0200

    libstdc++: Better CTAD for span and mdspan [PR120914].
    
    This implements P3029R1. In P3029R1, the CTAD for span is refined to
    permit deducing the extent of the span from an integral constant, e.g.
    
      span((T*) ptr, integral_constant<size_t, 5>{});
    
    is deduced as span<T, 5>. Similarly, in
    
      auto exts = extents(integral_constant<int, 2>);
      auto md = mdspan((T*) ptr, integral_constant<int, 2>);
    
    exts and md have types extents<size_t, 2> and mdspan<double,
    extents<size_t, 2>>, respectively.
    
            PR libstdc++/120914
    
    libstdc++-v3/ChangeLog:
    
            * include/std/span (span): Update CTAD to enable
            integral constants [P3029R1].
            * include/std/mdspan (extents): ditto.
            (mdspan): ditto.
            * testsuite/23_containers/span/deduction.cc: Test deduction
            guide.
            * testsuite/23_containers/mdspan/extents/misc.cc: ditto.
            * testsuite/23_containers/mdspan/mdspan.cc: ditto.
    
    Reviewed-by: Jonathan Wakely <jwak...@redhat.com>
    Reviewed-by: Tomasz KamiƄski <tkami...@redhat.com>
    Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com>

Diff:
---
 libstdc++-v3/include/std/mdspan                    |  8 ++-----
 libstdc++-v3/include/std/span                      | 20 ++++++++++++++++-
 .../testsuite/23_containers/mdspan/extents/misc.cc | 20 +++++++++++++++++
 .../testsuite/23_containers/mdspan/mdspan.cc       | 25 ++++++++++++++++++++++
 .../testsuite/23_containers/span/deduction.cc      |  3 +++
 5 files changed, 69 insertions(+), 7 deletions(-)

diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index 5a42aead3ebb..5d16de5d9072 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -406,10 +406,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     template<typename _IndexType, size_t... _Counts>
       auto __build_dextents_type(integer_sequence<size_t, _Counts...>)
        -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>;
-
-    template<typename _Tp>
-      consteval size_t
-      __dynamic_extent() { return dynamic_extent; }
   }
 
   template<typename _IndexType, size_t _Rank>
@@ -419,7 +415,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename... _Integrals>
     requires (is_convertible_v<_Integrals, size_t> && ...)
     explicit extents(_Integrals...) ->
-      extents<size_t, __mdspan::__dynamic_extent<_Integrals>()...>;
+      extents<size_t, __detail::__maybe_static_ext<_Integrals>...>;
 
   struct layout_left
   {
@@ -1316,7 +1312,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
              && (sizeof...(_Integrals) > 0)
     explicit mdspan(_ElementType*, _Integrals...)
     -> mdspan<_ElementType,
-             extents<size_t, __mdspan::__dynamic_extent<_Integrals>()...>>;
+             extents<size_t, __detail::__maybe_static_ext<_Integrals>...>>;
 
   template<typename _ElementType, typename _OIndexType, size_t _Nm>
     mdspan(_ElementType*, span<_OIndexType, _Nm>)
diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span
index 49ab9109d83e..5629a71b9bd2 100644
--- a/libstdc++-v3/include/std/span
+++ b/libstdc++-v3/include/std/span
@@ -476,6 +476,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 
   // deduction guides
+  namespace __detail
+  {
+    template<typename _Tp>
+      concept __integral_constant_like = is_integral_v<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)>
+       && bool_constant<_Tp() == _Tp::value>::value
+       && bool_constant<static_cast<decltype(_Tp::value)>(_Tp()) == _Tp::value>
+            ::value;
+
+    template<typename _Tp>
+      constexpr size_t __maybe_static_ext = dynamic_extent;
+
+    template<__integral_constant_like _Tp>
+      constexpr size_t __maybe_static_ext<_Tp> = {_Tp::value};
+  }
 
   template<typename _Type, size_t _ArrayExtent>
     span(_Type(&)[_ArrayExtent]) -> span<_Type, _ArrayExtent>;
@@ -489,7 +506,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<contiguous_iterator _Iter, typename _End>
     span(_Iter, _End)
-      -> span<remove_reference_t<iter_reference_t<_Iter>>>;
+      -> span<remove_reference_t<iter_reference_t<_Iter>>,
+                                __detail::__maybe_static_ext<_End>>;
 
   template<ranges::contiguous_range _Range>
     span(_Range &&)
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
index e71fdc542305..bca8901685d0 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
@@ -97,6 +97,25 @@ test_deduction(Extents... exts)
   VERIFY(e == expected);
 }
 
+constexpr bool
+test_integral_constant_deduction()
+{
+  auto verify = [](auto actual, auto expected)
+    {
+      static_assert(std::same_as<decltype(actual), decltype(expected)>);
+      VERIFY(actual == expected);
+    };
+
+  constexpr auto c1 = std::integral_constant<size_t, 1>{};
+  constexpr auto c2 = 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(c2), std::extents<size_t, 2>{});
+  verify(std::extents(c1, 2), std::extents<size_t, 1, dyn>{2});
+  return true;
+}
+
 constexpr bool
 test_deduction_all()
 {
@@ -104,6 +123,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();
   return true;
 }
 
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
index 9252273bf669..a650fb19bdf0 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
@@ -245,6 +245,28 @@ test_from_pointer_and_shape()
   return true;
 }
 
+constexpr bool
+test_from_pointer_and_integral_constant()
+{
+  std::array<double, 6> buffer{};
+  double * ptr = buffer.data();
+
+  auto verify = [ptr](auto actual, auto exts)
+    {
+      auto expected = std::mdspan<double, decltype(exts)>(ptr, exts);
+      static_assert(std::same_as<decltype(actual), decltype(expected)>);
+      VERIFY(actual.extents() == expected.extents());
+    };
+
+  auto c3 = std::integral_constant<int, 3>{};
+  auto c6 = 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));
+  return true;
+}
+
 constexpr bool
 test_from_extents()
 {
@@ -616,6 +638,9 @@ 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_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 dce6cedf89bd..c66db90222e6 100644
--- a/libstdc++-v3/testsuite/23_containers/span/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/span/deduction.cc
@@ -80,4 +80,7 @@ test01()
 
   std::span s12(const_cast<const std::span<int>&>(s5));
   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));
 }

Reply via email to