https://gcc.gnu.org/g:e920613db52adece7e3de5f2a2812247c72782f6

commit r16-8412-ge920613db52adece7e3de5f2a2812247c72782f6
Author: Tomasz Kamiński <[email protected]>
Date:   Mon Jan 26 12:20:48 2026 +0100

    libstdc++: Change meaning of strided_slice::extent per P3982R2
    
    This patch implements the changes suggested in P3982R2 (and PL007 NB 
comment)
    for C++26, but changing the strided_slice::extent to indicate number of
    elements (extent) in the produced (output) mdspan, instead of input.
    
    libstdc++-v3/ChangeLog:
    
            * include/std/mdspan (__mdspan::__static_slice_extent)
            (__mdspan::__dynamic_slice_extent): Return unmodified extent
            value for strided_slice.
            (__mdspan::__substrides_generic, 
__mdspan::__substrides_standardized):
            Multipliy stride, if more than one element is requested.
            (__mdspan::__canonical_range_slice): Define.
            (__mdspan::__slice_cast): Use __canonical_range_slice for 
range_slice
            and two elements tuples.
            (__mdspan::__check_inrange_index): Define.
            (__mdspan::__check_valid_slice): Validate if slice.offset +
            (slice.extent - 1) * slice.stride fits into extent of given
            dimension. Check stride if slice.extent > 1.
            * testsuite/23_containers/mdspan/submdspan/canonical_slices.cc:
            Add test for range_slice.
            * testsuite/23_containers/mdspan/submdspan/canonical_slices_neg.cc:
            Add tests validating new conditions.
            * testsuite/23_containers/mdspan/submdspan/selections/testcases.h:
            Adjusted for change of meaing of strided_slice::extent.
            * testsuite/23_containers/mdspan/submdspan/subextents.cc:
            Adjusted for change of meaing of strided_slice::extent. And expanded
            range_slice tests.
            * testsuite/23_containers/mdspan/submdspan/subextents_neg.cc:
            Adjusted for change of meaing of strided_slice::extent.
            * testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc:
            Adjust test for stride value.
    
    Reviewed-by: Jonathan Wakely <[email protected]>
    Signed-off-by: Tomasz Kamiński <[email protected]>

Diff:
---
 libstdc++-v3/include/std/mdspan                    | 199 ++++++++++++++-------
 .../mdspan/submdspan/canonical_slices.cc           | 160 +++++++++++++----
 .../mdspan/submdspan/canonical_slices_neg.cc       |  33 ++++
 .../mdspan/submdspan/selections/testcases.h        |  12 +-
 .../23_containers/mdspan/submdspan/subextents.cc   |  90 ++++++----
 .../mdspan/submdspan/subextents_neg.cc             |   6 +-
 .../mdspan/submdspan/submdspan_neg.cc              |   2 +-
 7 files changed, 363 insertions(+), 139 deletions(-)

diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index 7f02b3460546..5b80de2ca619 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -1001,10 +1001,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          return _Extent;
        else if constexpr (same_as<_Slice, constant_wrapper<_IndexType(0)>>)
          return 0;
-       else if constexpr (__is_constant_wrapper<typename _Slice::extent_type>
-                       && __is_constant_wrapper<typename _Slice::stride_type>)
-         return 1 + ((typename _Slice::extent_type{}) - 1)
-                  / (typename _Slice::stride_type{});
+       else if constexpr (__is_constant_wrapper<typename _Slice::extent_type>)
+         return _Slice::extent_type::value;
        else
          return dynamic_extent;
       }
@@ -1014,7 +1012,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __dynamic_slice_extent(const _Extents& __exts, _Slice __slice)
       {
        if constexpr (__is_strided_slice<_Slice>)
-         return __slice.extent == 0 ? 0 : 1 + (__slice.extent - 1) / 
__slice.stride;
+         return __slice.extent;
        else
          return __exts.extent(_K);
       }
@@ -1128,7 +1126,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            auto __stride = [&__mapping](size_t __k, auto __slice) -> _IndexType
            {
              if constexpr (__is_strided_slice<decltype(__slice)>)
-               if (__slice.stride < __slice.extent)
+               if (__slice.extent > 1)
                  return __mapping.stride(__k) * __slice.stride;
              return __mapping.stride(__k);
            };
@@ -1173,7 +1171,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                size_t __krev = _SubTrait::_S_idx(__k);
                if constexpr (__is_strided_slice<decltype(__slice)>)
                  {
-                   if (__slice.stride < __slice.extent)
+                   if (__slice.extent > 1)
                      __ret[__krev] = __stride * __slice.stride;
                    else
                      __ret[__krev] = __stride;
@@ -3293,6 +3291,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          return __mdspan::__index_type_cast<_IndexType>(std::move(__slice));
       }
 
+    template<typename _IndexType, 
+           typename _OffsetType, typename _SpanType, typename _StrideType>
+    constexpr auto
+    __canonical_range_slice(_OffsetType __offset, _SpanType __span,
+                           _StrideType __stride)
+    {
+      if constexpr (is_same_v<_SpanType, constant_wrapper<_IndexType(0)>>
+                   || is_same_v<_StrideType, constant_wrapper<_IndexType(1)>>)
+       return strided_slice{
+         .offset = __offset,
+         .extent = __span,
+         .stride = cw<_IndexType(1)>
+       };
+      else if constexpr (__is_constant_wrapper<_StrideType>)
+        {
+         static_assert(_StrideType::value > 0);
+         if constexpr (__is_constant_wrapper<_SpanType>)
+           return strided_slice{
+             .offset = __offset,
+             .extent = cw<_IndexType(1 + (_SpanType::value - 1) / 
_StrideType::value)>,
+             .stride = __stride
+           };
+         else
+           return strided_slice{
+             .offset = __offset,
+             .extent = _IndexType(__span > 0 ? 1 + (__span - 1) / 
_StrideType::value : 0),
+             .stride = __stride
+           };
+        }
+      else if (__span == 0 || __stride == 1)
+       return strided_slice{
+         .offset = __offset,
+         .extent = _IndexType(__span),
+         .stride = _IndexType(1)
+       };
+      else
+        {
+         __glibcxx_assert(__stride > 0);
+         return strided_slice{
+           .offset = __offset,
+           .extent = _IndexType(1 + (__span - 1) / __stride),
+           .stride = __stride
+         };
+       }
+    }
+
     template<typename _IndexType, typename _Slice>
       constexpr auto
       __slice_cast(_Slice&& __slice)
@@ -3303,52 +3347,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        else if constexpr (is_convertible_v<_SliceType, _IndexType>)
          return __mdspan::__canonical_index<_IndexType>(std::move(__slice));
        else if constexpr (__is_strided_slice<_SliceType>)
-         {
-           auto __extent
-             = 
__mdspan::__canonical_index<_IndexType>(std::move(__slice.extent));
-           auto __offset
-             = 
__mdspan::__canonical_index<_IndexType>(std::move(__slice.offset));
-           if constexpr (is_same_v<decltype(__extent),
-                                   constant_wrapper<_IndexType(0)>>)
-             return strided_slice{
-               .offset = __offset,
-               .extent = __extent,
-               .stride = cw<_IndexType(1)>
-             };
-           else
-             return strided_slice{
-               .offset = __offset,
-               .extent = __extent,
-               .stride
-                 = 
__mdspan::__canonical_index<_IndexType>(std::move(__slice.stride))
-             };
-         }
+         return strided_slice{
+           .offset = 
__mdspan::__canonical_index<_IndexType>(std::move(__slice.offset)),
+           .extent = 
__mdspan::__canonical_index<_IndexType>(std::move(__slice.extent)),
+           .stride = 
__mdspan::__canonical_index<_IndexType>(std::move(__slice.stride))
+         };
        else if constexpr (__is_range_slice<_SliceType>)
          {
            auto __first
              = 
__mdspan::__canonical_index<_IndexType>(std::move(__slice.first));
            auto __last
              = 
__mdspan::__canonical_index<_IndexType>(std::move(__slice.last));
-           auto __stride
-             = 
__mdspan::__canonical_index<_IndexType>(std::move(__slice.stride));
-            return __mdspan::__slice_cast<_IndexType>(
-                    strided_slice{__first, __last - __first, __stride});
+           return __mdspan::__canonical_range_slice<_IndexType>(
+                    __first,
+                    __mdspan::__canonical_index<_IndexType>(__last - __first),
+                    
__mdspan::__canonical_index<_IndexType>(std::move(__slice.stride)));
          }
        else
          {
            auto [__sbegin, __send] = std::move(__slice);
-           auto __offset
+           auto __cbegin
              = __mdspan::__canonical_index<_IndexType>(std::move(__sbegin));
-           auto __end
+           auto __cend
              = __mdspan::__canonical_index<_IndexType>(std::move(__send));
-           return strided_slice{
-             .offset = __offset,
-             .extent = __mdspan::__canonical_index<_IndexType>(__end - 
__offset),
-             .stride = cw<_IndexType(1)>
-           };
+           auto __cspan
+             = __mdspan::__canonical_index<_IndexType>(__cend - __cbegin);
+           return __mdspan::__canonical_range_slice<_IndexType>(
+                    __cbegin, __cspan, cw<_IndexType(1)>);
          }
       }
 
+   template<typename _IndexType, size_t _Extent, typename _OIndexType>
+      constexpr void
+      __check_inrange_index(const extents<_IndexType, _Extent>& __ext,
+                          const _OIndexType& __idx)
+      {
+       if constexpr (__is_constant_wrapper<_OIndexType>
+                     && _Extent != dynamic_extent)
+         {
+           static_assert(_OIndexType::value >= 0);
+           static_assert(std::cmp_less(_OIndexType::value, _Extent));
+         }
+       else
+         __glibcxx_assert(__idx < __ext.extent(0));
+      }
+
     template<typename _IndexType, size_t _Extent, typename _OIndexType>
       constexpr void
       __check_valid_index(const extents<_IndexType, _Extent>& __ext,
@@ -3362,7 +3405,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          }
        else
          __glibcxx_assert(__idx <= __ext.extent(0));
-}
+      }
 
     template<typename _IndexType, size_t _Extent, typename _Slice>
       constexpr void
@@ -3371,34 +3414,68 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       {
        if constexpr (__is_strided_slice<_Slice>)
          {
+           __mdspan::__check_valid_index(__ext, __slice.extent);
            // DEVIATION: For empty slices, P3663r3 does not allow us to check
            // that this is less than or equal to the k-th extent (at runtime).
            // We're only allowed to check if __slice.offset, __slice.extent
            // are constant wrappers and __ext is a static extent.
-           __mdspan::__check_valid_index(__ext, __slice.offset);
-           __mdspan::__check_valid_index(__ext, __slice.extent);
-
-           if constexpr (__is_constant_wrapper<typename _Slice::extent_type>
-                         && __is_constant_wrapper<typename 
_Slice::stride_type>)
-             static_assert(_Slice::stride_type::value > 0);
-           else
-             __glibcxx_assert(__slice.extent == 0 || __slice.stride > 0);
-
-           if constexpr (__is_constant_wrapper<typename _Slice::offset_type>
-               && __is_constant_wrapper<typename _Slice::extent_type>
-               && _Extent != dynamic_extent)
-             static_assert(std::cmp_greater_equal(
-                 _Extent - _Slice::offset_type::value,
-                 _Slice::extent_type::value));
+           if constexpr (is_same_v<typename _Slice::extent_type,
+                                   constant_wrapper<_IndexType(0)>>)
+             __mdspan::__check_valid_index(__ext, __slice.offset);
+           else if constexpr (is_same_v<typename _Slice::extent_type,
+                                        constant_wrapper<_IndexType(1)>>)
+              __mdspan::__check_inrange_index(__ext, __slice.offset);
+           else if constexpr (__is_constant_wrapper<typename 
_Slice::extent_type>)
+             { 
+               __mdspan::__check_inrange_index(__ext, __slice.offset);
+               if constexpr (__is_constant_wrapper<typename 
_Slice::stride_type>)
+                 static_assert(_Slice::stride_type::value > 0);
+               else
+                 __glibcxx_assert(__slice.stride > 0);
+
+               if constexpr (_Extent != dynamic_extent
+                    && __is_constant_wrapper<typename _Slice::offset_type>)
+                  static_assert(std::cmp_greater_equal(
+                   _Extent - _Slice::offset_type::value,
+                   _Slice::extent_type::value));
+               if constexpr (_Extent != dynamic_extent
+                    && __is_constant_wrapper<typename _Slice::stride_type>)
+                  static_assert(std::cmp_greater(
+                   _Extent,
+                   (_Slice::extent_type::value - 1) * 
_Slice::stride_type::value));
+
+               if constexpr (_Extent != dynamic_extent
+                    && __is_constant_wrapper<typename _Slice::offset_type>
+                    && __is_constant_wrapper<typename _Slice::stride_type>)
+                  static_assert(std::cmp_greater(
+                   _Extent - _Slice::offset_type::value,
+                   (_Slice::extent_type::value - 1) * 
_Slice::stride_type::value));
+               else
+                 __glibcxx_assert(std::cmp_greater(
+                   __ext.extent(0) - __slice.offset,
+                   (_Slice::extent_type::value - 1) * __slice.stride));
+             }
+           else if constexpr (is_same_v<typename _Slice::stride_type,
+                                         constant_wrapper<_IndexType(1)>>)
+             {
+               __mdspan::__check_valid_index(__ext, __slice.offset);
+               __glibcxx_assert(std::cmp_greater_equal(
+                 __ext.extent(0) - __slice.offset,
+                 __slice.extent));
+              }
+           else if (__slice.extent == 0)
+             __mdspan::__check_valid_index(__ext, __slice.offset);
            else
-             __glibcxx_assert(__ext.extent(0) - __slice.offset
-                              >= __slice.extent);
+             {
+               __glibcxx_assert(__slice.offset < __ext.extent(0));
+               __glibcxx_assert(__slice.extent == 1 || __slice.stride > 0);
+               __glibcxx_assert(__slice.extent == 1 || std::cmp_greater(
+                 __ext.extent(0) - __slice.offset,
+                 (__slice.extent - 1) * __slice.stride));
+             }
          }
-       else if constexpr (__is_constant_wrapper<_Slice>
-                          && _Extent != dynamic_extent)
-         static_assert(std::cmp_less(_Slice::value, _Extent));
-       else if constexpr (convertible_to<_Slice, _IndexType>)
-         __glibcxx_assert(__slice < __ext.extent(0));
+       else if constexpr (!is_same_v<_Slice, full_extent_t>)
+          __mdspan::__check_inrange_index(__ext, __slice);
       }
 
     template<typename _Extents, typename... _Slices>
diff --git 
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices.cc
index 5ca123eee506..7e6a0791af7d 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices.cc
@@ -114,90 +114,184 @@ test_pair_all()
 {
   test_pair<std::pair>();
   test_pair<std::tuple>();
+  test_pair<std::range_slice>();
   test_pair<Range>();
   return true;
 }
 
+template<template<typename, typename, typename> typename Triple>
 constexpr bool
-test_strided_slice(auto exts, auto co, auto ce, auto cs)
+test_triple(auto exts, auto ce, auto cf, auto cl, auto cs)
 {
   using IndexType = decltype(exts)::index_type;
 
-  auto coffset = std::cw<IndexType{co.value}>;
+  auto coffset = std::cw<IndexType{cf.value}>;
   auto cextent = std::cw<IndexType{ce.value}>;
   auto cstride = std::cw<IndexType{cs.value}>;
 
-  auto raw_ccc = std::strided_slice{co, ce, cs};
+  auto raw_ccc = Triple{cf, cl, cs};
   auto [ccc] = std::canonical_slices(exts, raw_ccc);
   assert_same(ccc.offset, coffset);
   assert_same(ccc.extent, cextent);
   assert_same(ccc.stride, cstride);
 
-  auto raw_dcc = std::strided_slice{co.value, ce, cs};
+  auto raw_dcc = Triple{cf.value, cl, cs};
   auto [dcc] = std::canonical_slices(exts, raw_dcc);
   assert_same(dcc.offset, coffset.value);
-  assert_same(dcc.extent, cextent);
+  assert_same(dcc.extent, cextent.value);
   assert_same(dcc.stride, cstride);
 
-  auto raw_cdc = std::strided_slice{co, ce.value, cs};
+  auto raw_cdc = Triple{cf, cl.value, cs};
   auto [cdc] = std::canonical_slices(exts, raw_cdc);
   assert_same(cdc.offset, coffset);
   assert_same(cdc.extent, cextent.value);
   assert_same(cdc.stride, cstride);
 
-  auto raw_ccd = std::strided_slice{co, ce, cs.value};
+  auto raw_ccd = Triple{cf, cl, cs.value};
   auto [ccd] = std::canonical_slices(exts, raw_ccd);
   assert_same(ccd.offset, coffset);
-  assert_same(ccd.extent, cextent);
+  assert_same(ccd.extent, cextent.value);
   assert_same(ccd.stride, cstride.value);
   return true;
 }
 
+template<template<typename, typename, typename> typename Triple>
 constexpr bool
-test_strided_slice()
+test_triple_zero_extent(auto exts, auto cf, auto cs)
 {
-  auto run = [](auto exts)
+  using IndexType = typename decltype(exts)::index_type;
+  auto raw_ccc = Triple{cf, cf, cs};
+  auto [ccc] = std::canonical_slices(exts, raw_ccc);
+  assert_same(ccc.stride, std::cw<IndexType{1}>);
+
+  auto raw_ccd = Triple{cf, cf, cs.value};
+  auto [ccd] = std::canonical_slices(exts, raw_ccd);
+  assert_same(ccd.stride, std::cw<IndexType{1}>);
+
+  auto raw_cdd = Triple{cf, cf.value, cs.value};
+  auto [cdd] = std::canonical_slices(exts, raw_cdd);
+  assert_same(cdd.stride, IndexType(1));
+
+  auto raw_dcd = Triple{cf.value, cf, cs.value};
+  auto [dcd] = std::canonical_slices(exts, raw_dcd);
+  assert_same(dcd.stride, IndexType(1));
+
+  auto raw_ddd = Triple{cf.value, cf.value, cs.value};
+  auto [ddd] = std::canonical_slices(exts, raw_ddd);
+  assert_same(cdd.stride, IndexType(1));
+
+  if constexpr (decltype(cs)::value > 0)
   {
-    auto cs = std::cw<uint8_t{9}>;
-    test_strided_slice(exts, std::cw<uint8_t{2}>, std::cw<uint8_t{3}>, cs);
-    test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{5}>, cs);
-  };
+    auto cstride = std::cw<IndexType(cs.value)>;
+
+    auto raw_cdc = Triple{cf, cf.value, cs};
+    auto [cdc] = std::canonical_slices(exts, raw_cdc);
+    assert_same(cdc.stride, cstride);
+
+    auto raw_dcc = Triple{cf.value, cf, cs};
+    auto [dcc] = std::canonical_slices(exts, raw_dcc);
+    assert_same(dcc.stride, cstride);
+
+    auto raw_ddc = Triple{cf.value, cf.value, cs};
+    auto [ddc] = std::canonical_slices(exts, raw_ddc);
+    assert_same(cdc.stride, cstride);
+  }
 
+  return true;
+}
+
+template<template<typename, typename, typename> typename Triple>
+constexpr bool
+test_triple()
+{
+  auto run = [](auto exts) {
+    test_triple<Triple>(exts, std::cw<uint8_t{5}>,
+      std::cw<uint8_t{0}>, std::cw<uint8_t{5}>, std::cw<uint8_t{1}>);
+    test_triple<Triple>(exts, std::cw<uint8_t{3}>,
+      std::cw<uint8_t{0}>, std::cw<uint8_t{5}>, std::cw<uint8_t{2}>);
+    test_triple<Triple>(exts, std::cw<uint8_t{2}>,
+      std::cw<uint8_t{1}>, std::cw<uint8_t{5}>, std::cw<uint8_t{3}>);
+    test_triple<Triple>(exts, std::cw<uint8_t{1}>,
+      std::cw<uint8_t{1}>, std::cw<uint8_t{5}>, std::cw<uint8_t{9}>);
+
+    test_triple_zero_extent<Triple>(exts, 
+      std::cw<uint8_t{0}>, std::cw<uint8_t{9}>);
+    test_triple_zero_extent<Triple>(exts,
+      std::cw<uint8_t{0}>, std::cw<uint8_t{0}>);
+    test_triple_zero_extent<Triple>(exts,
+      std::cw<uint8_t{5}>, std::cw<uint8_t{9}>);
+    test_triple_zero_extent<Triple>(exts,
+      std::cw<uint8_t{5}>, std::cw<uint8_t{0}>);
+  };
   run(std::extents<int, 5>{});
   run(std::extents<int, dyn>{5});
+
+  test_triple_zero_extent<Triple>(std::extents<int, 0>{}, 
+    std::cw<uint8_t{0}>, std::cw<uint8_t{9}>);
+  test_triple_zero_extent<Triple>(std::extents<int, dyn>{0},
+    std::cw<uint8_t{0}>, std::cw<uint8_t{0}>);
+
   return true;
 }
 
 constexpr bool
-test_strided_slice_zero_extent(auto exts, auto cs)
+test_triple_all()
 {
-  using IndexType = typename decltype(exts)::index_type;
-  auto c0 = std::cw<uint8_t{0}>;
-  auto raw_ccc = std::strided_slice{c0, c0, cs};
-  auto [ccc] = std::canonical_slices(exts, raw_ccc);
-  assert_same(ccc.stride, std::cw<IndexType{1}>);
-
-  auto raw_ccd = std::strided_slice{c0, c0, cs.value};
-  auto [ccd] = std::canonical_slices(exts, raw_ccd);
-  assert_same(ccd.stride, std::cw<IndexType{1}>);
+  test_triple<std::range_slice>();
   return true;
 }
 
 constexpr bool
-test_strided_slice_zero_extent(auto exts)
+test_strided_slice(auto exts, auto co, auto ce, auto cs)
 {
-  test_strided_slice_zero_extent(exts, std::cw<uint8_t{0}>);
-  test_strided_slice_zero_extent(exts, std::cw<uint8_t{9}>);
+  using IndexType = decltype(exts)::index_type;
+
+  auto coffset = std::cw<IndexType{co.value}>;
+  auto cextent = std::cw<IndexType{ce.value}>;
+  auto cstride = std::cw<IndexType{cs.value}>;
+
+  auto raw_ccc = std::strided_slice{co, ce, cs};
+  auto [ccc] = std::canonical_slices(exts, raw_ccc);
+  assert_same(ccc.offset, coffset);
+  assert_same(ccc.extent, cextent);
+  assert_same(ccc.stride, cstride);
+
+  auto raw_dcc = std::strided_slice{co.value, ce, cs};
+  auto [dcc] = std::canonical_slices(exts, raw_dcc);
+  assert_same(dcc.offset, coffset.value);
+  assert_same(dcc.extent, cextent);
+  assert_same(dcc.stride, cstride);
+
+  auto raw_cdc = std::strided_slice{co, ce.value, cs};
+  auto [cdc] = std::canonical_slices(exts, raw_cdc);
+  assert_same(cdc.offset, coffset);
+  assert_same(cdc.extent, cextent.value);
+  assert_same(cdc.stride, cstride);
+
+  auto raw_ccd = std::strided_slice{co, ce, cs.value};
+  auto [ccd] = std::canonical_slices(exts, raw_ccd);
+  assert_same(ccd.offset, coffset);
+  assert_same(ccd.extent, cextent);
+  assert_same(ccd.stride, cstride.value);
   return true;
 }
 
 constexpr bool
-test_strided_slice_zero_extent()
+test_strided_slice()
 {
-  test_strided_slice_zero_extent(std::extents<int, 0>{});
-  test_strided_slice_zero_extent(std::extents<int, dyn>{0});
-  test_strided_slice_zero_extent(std::extents<int, 5>{});
-  test_strided_slice_zero_extent(std::extents<int, dyn>{5});
+  auto run = [](auto exts)
+  {
+    auto cs = std::cw<uint8_t{1}>;
+    test_strided_slice(exts, std::cw<uint8_t{2}>, std::cw<uint8_t{2}>, 
std::cw<uint8_t{2}>);
+    test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{5}>, 
std::cw<uint8_t{1}>);
+    test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{0}>, 
std::cw<uint8_t{1}>);
+    test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{0}>, 
std::cw<uint8_t{3}>);
+    test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{0}>, 
std::cw<uint8_t{0}>);
+    test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{0}>, 
std::cw<uint8_t{9}>);
+  };
+
+  run(std::extents<int, 5>{});
+  run(std::extents<int, dyn>{5});
   return true;
 }
 
@@ -206,8 +300,8 @@ test_all()
 {
   test_scalar();
   test_pair_all();
+  test_triple_all();
   test_strided_slice();
-  test_strided_slice_zero_extent();
   return true;
 }
 
diff --git 
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices_neg.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices_neg.cc
index 6dbfd5e8a1b8..3923d5393b9e 100644
--- 
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices_neg.cc
+++ 
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices_neg.cc
@@ -112,6 +112,7 @@ template<typename Offset, typename Extent, typename Stride, 
typename Extents>
 constexpr auto i8_6 = int8_t{6};
 constexpr auto c_i8_6 = std::cw<int8_t{6}>;
 constexpr auto c2 = std::cw<2>;
+constexpr auto c3 = std::cw<3>;
 constexpr auto c4 = std::cw<4>;
 
 static_assert(test_over2(i8_6, 0, 1, dyn_uexts));    // { dg-error "expansion 
of" }
@@ -122,6 +123,14 @@ static_assert(test_over2(0, c_i8_6, 1, dyn_uexts));  // { 
dg-error "expansion of
 static_assert(test_over2(c2, 4, 1, dyn_uexts));      // { dg-error "expansion 
of" }
 static_assert(test_over2(2, c4, 1, dyn_uexts));      // { dg-error "expansion 
of" }
 static_assert(test_over2(c2, c4, 1, dyn_uexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(2, 3, 2, dyn_uexts));       // { dg-error "expansion 
of" }
+static_assert(test_over2(2, 3, c2, dyn_uexts));      // { dg-error "expansion 
of" }
+static_assert(test_over2(2, c3, 2, dyn_uexts));      // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, 3, 2, dyn_uexts));      // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, c3, 2, dyn_uexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(2, c3, c2, dyn_uexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, 3, c2, dyn_uexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, c3, c2, dyn_uexts));    // { dg-error "expansion 
of" }
 
 static_assert(test_over2(i8_6, 0, 1, dyn_sexts));    // { dg-error "expansion 
of" }
 static_assert(test_over2(0, i8_6, 1, dyn_sexts));    // { dg-error "expansion 
of" }
@@ -131,6 +140,14 @@ static_assert(test_over2(0, c_i8_6, 1, dyn_sexts));  // { 
dg-error "expansion of
 static_assert(test_over2(c2, 4, 1, dyn_sexts));      // { dg-error "expansion 
of" }
 static_assert(test_over2(2, c4, 1, dyn_sexts));      // { dg-error "expansion 
of" }
 static_assert(test_over2(c2, c4, 1, dyn_sexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(2, 3, 2, dyn_sexts));       // { dg-error "expansion 
of" }
+static_assert(test_over2(2, 3, c2, dyn_sexts));      // { dg-error "expansion 
of" }
+static_assert(test_over2(2, c3, 2, dyn_sexts));      // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, 3, 2, dyn_sexts));      // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, c3, 2, dyn_sexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(2, c3, c2, dyn_sexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, 3, c2, dyn_sexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, c3, c2, dyn_sexts));    // { dg-error "expansion 
of" }
 
 static_assert(test_over2(i8_6, 0, 1, sta_uexts));    // { dg-error "expansion 
of" }
 static_assert(test_over2(0, i8_6, 1, sta_uexts));    // { dg-error "expansion 
of" }
@@ -140,6 +157,14 @@ static_assert(test_over2(0, c_i8_6, 1, sta_uexts));  // { 
dg-error "expansion of
 static_assert(test_over2(c2, 4, 1, sta_uexts));      // { dg-error "expansion 
of" }
 static_assert(test_over2(2, c4, 1, sta_uexts));      // { dg-error "expansion 
of" }
 static_assert(test_over2(c2, c4, 1, sta_uexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(2, 3, 2, sta_uexts));       // { dg-error "expansion 
of" }
+static_assert(test_over2(2, 3, c2, sta_uexts));      // { dg-error "expansion 
of" }
+static_assert(test_over2(2, c3, 2, sta_uexts));      // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, 3, 2, sta_uexts));      // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, c3, 2, sta_uexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(2, c3, c2, sta_uexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, 3, c2, sta_uexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, c3, c2, sta_uexts));    // { dg-error "from here" 
}
 
 static_assert(test_over2(i8_6, 0, 1, sta_sexts));    // { dg-error "expansion 
of" }
 static_assert(test_over2(0, i8_6, 1, sta_sexts));    // { dg-error "expansion 
of" }
@@ -149,6 +174,14 @@ static_assert(test_over2(0, c_i8_6, 1, sta_sexts));  // { 
dg-error "expansion of
 static_assert(test_over2(c2, 4, 1, sta_sexts));      // { dg-error "expansion 
of" }
 static_assert(test_over2(2, c4, 1, sta_sexts));      // { dg-error "expansion 
of" }
 static_assert(test_over2(c2, c4, 1, sta_sexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(2, 3, 2, sta_sexts));       // { dg-error "expansion 
of" }
+static_assert(test_over2(2, 3, c2, sta_sexts));      // { dg-error "expansion 
of" }
+static_assert(test_over2(2, c3, 2, sta_sexts));      // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, 3, 2, sta_sexts));      // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, c3, 2, sta_sexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(2, c3, c2, sta_sexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, 3, c2, sta_sexts));     // { dg-error "expansion 
of" }
+static_assert(test_over2(c2, c3, c2, sta_sexts));    // { dg-error "from here" 
}
 
 // Checks the precondition: offset + extent <= exts.extent(0) for unsigned
 // index_type when offset + extent overflows.
diff --git 
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h 
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h
index d7b751d700c0..eade9017e039 100644
--- 
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h
+++ 
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h
@@ -292,10 +292,10 @@ template<typename Layout>
       check_selection<Layout>(exts, collapse{}, s, collapse{});
     };
 
+    check(std::strided_slice(0, 1, 2));
     check(std::strided_slice(0, 2, 2));
-    check(std::strided_slice(0, 3, 2));
-    check(std::strided_slice(1, 3, 2));
-    check(std::strided_slice(1, std::cw<3>, std::cw<2>));
+    check(std::strided_slice(1, 2, 2));
+    check(std::strided_slice(1, std::cw<2>, std::cw<2>));
     return true;
   }
 
@@ -303,9 +303,9 @@ template<typename Layout>
   constexpr bool
   test_strided_box_selection(auto exts)
   {
-    auto s0 = std::strided_slice(0, 3, 2);
-    auto s1 = std::strided_slice(1, 4, 2);
-    auto s2 = std::strided_slice(0, 7, 3);
+    auto s0 = std::strided_slice(0, 2, 2);
+    auto s1 = std::strided_slice(1, 2, 2);
+    auto s2 = std::strided_slice(0, 3, 3);
 
     check_selection<Layout>(exts, s0, s1, s2);
     return true;
diff --git 
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc
index 464b253ff4d8..379fb79dfc23 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc
@@ -21,7 +21,7 @@ test_from_full_extent()
 
 template<template<typename, typename> typename Pair, template<int> typename Cw>
   constexpr bool
-  test_from_tuple()
+  test_from_pair()
   {
     auto exts = std::extents<int, 3, 5, 7>{};
     auto s0 = Cw<1>{};
@@ -29,22 +29,22 @@ template<template<typename, typename> typename Pair, 
template<int> typename Cw>
     auto s2 = Pair{Cw<1>{}, 4};
     auto sub_exts = std::subextents(exts, s0, s1, s2);
     VERIFY(sub_exts.rank() == 2);
-    VERIFY(sub_exts.static_extent(0) == size_t(get<1>(s1) - get<0>(s1)));
+    VERIFY(sub_exts.static_extent(0) == 1);
     VERIFY(sub_exts.static_extent(1) == dyn);
-    VERIFY(std::cmp_equal(sub_exts.extent(1), get<1>(s2) - get<0>(s2)));
+    VERIFY(std::cmp_equal(sub_exts.extent(1), 3));
     return true;
   }
 
 template<template<int> typename Cw>
   constexpr bool
-  test_from_tuple_all()
+  test_from_pair_all()
   {
-    test_from_tuple<std::tuple, Cw>();
-    test_from_tuple<std::pair, Cw>();
+    test_from_pair<std::tuple, Cw>();
+    test_from_pair<std::pair, Cw>();
+    test_from_pair<std::range_slice, Cw>();
     return true;
   }
 
-
 template<typename Int>
   void
   test_from_int_like_as_scalar()
@@ -104,45 +104,57 @@ template<template<int> typename Cw>
       VERIFY(sub_exts.rank() == 2);
       VERIFY(sub_exts.static_extent(0) == dyn);
       VERIFY(sub_exts.extent(0) == 2);
-      VERIFY(sub_exts.static_extent(1) == dyn);
-      VERIFY(sub_exts.extent(1) == 2);
+      VERIFY(sub_exts.static_extent(1) == 2);
     }
 
     {
       // selected = 1 x [1, 3] x [1, 4, 7, 10]
       auto s0 = 1;
-      auto s1 = std::strided_slice{1, Cw<4>{}, 2};
-      auto s2 = std::strided_slice{1, Cw<10>{}, Cw<3>{}};
+      auto s1 = std::strided_slice{1, Cw<2>{}, 2};
+      auto s2 = std::strided_slice{1, Cw<4>{}, Cw<3>{}};
       auto sub_exts = std::subextents(exts, s0, s1, s2);
       VERIFY(sub_exts.rank() == 2);
-      VERIFY(sub_exts.static_extent(0) == dyn);
-      VERIFY(sub_exts.extent(0) == 2);
+      VERIFY(sub_exts.static_extent(0) == 2);
       VERIFY(sub_exts.static_extent(1) == 4);
     }
 
     {
       // selected = [0, 2] x [1, 3] x [0, 3, 6]
-      auto s0 = std::strided_slice(0, 3, 2);
-      auto s1 = std::strided_slice(1, 4, 2);
-      auto s2 = std::strided_slice(0, 7, 3);
+      auto s0 = std::strided_slice(0, 2, 2);
+      auto s1 = std::strided_slice(1, 2, 2);
+      auto s2 = std::strided_slice(0, 3, 3);
       auto sub_exts = std::subextents(exts, s0, s1, s2);
       VERIFY(sub_exts.rank() == 3);
       VERIFY(sub_exts.extent(0) == 2);
       VERIFY(sub_exts.extent(1) == 2);
       VERIFY(sub_exts.extent(2) == 3);
     }
+
+    {
+      // selected = [0] x [1] x [2]
+      auto s0 = std::strided_slice(0, 1, 99);
+      auto s1 = std::strided_slice(1, 1, 99);
+      auto s2 = std::strided_slice(2, 1, 99);
+      auto sub_exts = std::subextents(exts, s0, s1, s2);
+      VERIFY(sub_exts.rank() == 3);
+      VERIFY(sub_exts.extent(0) == 1);
+      VERIFY(sub_exts.extent(1) == 1);
+      VERIFY(sub_exts.extent(2) == 1);
+    }
+
     return true;
   }
 
-template<template<int> typename Cw>
+template<template<typename, typename, typename> class Triple,
+        template<int> typename Cw>
   constexpr bool
-  test_from_range_slice()
+  test_from_triple()
   {
     auto exts = std::extents<int, 5, 7, 11>{};
     {
       auto s0 = 1;
-      auto s1 = std::range_slice{0, 0, 0};
-      auto s2 = std::range_slice{Cw<1>{}, Cw<1>{}, 0};
+      auto s1 = Triple{0, 0, 0};
+      auto s2 = Triple{Cw<1>{}, Cw<1>{}, 0};
       auto sub_exts = std::subextents(exts, s0, s1, s2);
       VERIFY(sub_exts.rank() == 2);
       VERIFY(sub_exts.static_extent(0) == dyn);
@@ -152,8 +164,8 @@ template<template<int> typename Cw>
 
     {
       auto s0 = 1;
-      auto s1 = std::range_slice{0, 2, Cw<1>{}};
-      auto s2 = std::range_slice{1, Cw<3>{}};
+      auto s1 = Triple{0, 2, Cw<1>{}};
+      auto s2 = Triple{1, Cw<3>{}, Cw<1>{}};
       auto sub_exts = std::subextents(exts, s0, s1, s2);
       VERIFY(sub_exts.rank() == 2);
       VERIFY(sub_exts.static_extent(0) == dyn);
@@ -164,8 +176,8 @@ template<template<int> typename Cw>
 
     {
       auto s0 = 1;
-      auto s1 = std::range_slice{0, 2, Cw<1>{}};
-      auto s2 = std::range_slice{Cw<1>{}, Cw<3>{}, 1};
+      auto s1 = Triple{0, 2, Cw<1>{}};
+      auto s2 = Triple{Cw<1>{}, Cw<3>{}, 1};
       auto sub_exts = std::subextents(exts, s0, s1, s2);
       VERIFY(sub_exts.rank() == 2);
       VERIFY(sub_exts.static_extent(0) == dyn);
@@ -177,8 +189,8 @@ template<template<int> typename Cw>
     {
       // selected = 1 x [1, 3] x [1, 4, 7, 10]
       auto s0 = 1;
-      auto s1 = std::range_slice{1, Cw<5>{}, 2};
-      auto s2 = std::range_slice{1, Cw<11>{}, Cw<3>{}};
+      auto s1 = Triple{1, Cw<5>{}, 2};
+      auto s2 = Triple{1, Cw<11>{}, Cw<3>{}};
       auto sub_exts = std::subextents(exts, s0, s1, s2);
       VERIFY(sub_exts.rank() == 2);
       VERIFY(sub_exts.static_extent(0) == dyn);
@@ -190,8 +202,8 @@ template<template<int> typename Cw>
     {
       // selected = 1 x [1, 3] x [1, 4, 7, 10]
       auto s0 = 1;
-      auto s1 = std::range_slice{1, Cw<5>{}, 2};
-      auto s2 = std::range_slice{Cw<1>{}, Cw<11>{}, Cw<3>{}};
+      auto s1 = Triple{1, Cw<5>{}, 2};
+      auto s2 = Triple{Cw<1>{}, Cw<11>{}, Cw<3>{}};
       auto sub_exts = std::subextents(exts, s0, s1, s2);
       VERIFY(sub_exts.rank() == 2);
       VERIFY(sub_exts.static_extent(0) == dyn);
@@ -201,18 +213,26 @@ template<template<int> typename Cw>
 
     {
       // selected = [0, 2] x [1, 3] x [0, 3, 6]
-      auto s0 = std::range_slice(0, 3, 2);
-      auto s1 = std::range_slice(1, 5, 2);
-      auto s2 = std::range_slice(0, 7, 3);
+      auto s0 = Triple{0, 3, 2};
+      auto s1 = Triple{1, 5, 2};
+      auto s2 = Triple{0, 7, 3};
       auto sub_exts = std::subextents(exts, s0, s1, s2);
       VERIFY(sub_exts.rank() == 3);
       VERIFY(sub_exts.extent(0) == 2);
       VERIFY(sub_exts.extent(1) == 2);
       VERIFY(sub_exts.extent(2) == 3);
     }
+
     return true;
   }
 
+template<template<int> typename Cw>
+  constexpr bool
+  test_from_triple_all()
+  {
+    test_from_triple<std::range_slice, Cw>();
+    return true;
+  }
 
 template<int Value>
   using CW = std::constant_wrapper<Value, int>;
@@ -224,14 +244,14 @@ constexpr bool
 test_all()
 {
   test_from_full_extent();
-  test_from_tuple_all<CW>();
-  test_from_tuple_all<IC>();
+  test_from_pair_all<CW>();
+  test_from_pair_all<IC>();
   test_from_const_int<CW>();
   test_from_const_int<IC>();
   test_from_strided_slice<CW>();
   test_from_strided_slice<IC>();
-  test_from_range_slice<CW>();
-  test_from_range_slice<IC>();
+  test_from_triple_all<CW>();
+  test_from_triple_all<IC>();
   test_from_int_like_in_tuple<StructuralInt>();
   return true;
 }
diff --git 
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents_neg.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents_neg.cc
index c81a1383e3cb..5b11424680df 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents_neg.cc
@@ -19,7 +19,7 @@ constexpr bool
 test_invalid_stride_zero()
 {
   auto exts = std::extents(3, 5, 7);
-  auto s = std::strided_slice{0, 1, 0};
+  auto s = std::strided_slice{0, 2, 0};
   auto sub_exts = std::subextents(exts, 1, s, 2);  // { dg-error "expansion 
of" }
   return true;
 }
@@ -34,9 +34,9 @@ test_out_of_bounds(const Slice& slice)
   return true;
 }
 static_assert(test_out_of_bounds(std::strided_slice{0, 6, 1}));  // { dg-error 
"expansion of" }
-static_assert(test_out_of_bounds(std::strided_slice{0, 7, 2}));  // { dg-error 
"expansion of" }
+static_assert(test_out_of_bounds(std::strided_slice{0, 4, 2}));  // { dg-error 
"expansion of" }
 static_assert(test_out_of_bounds(std::strided_slice{1, 6, 1}));  // { dg-error 
"expansion of" }
-static_assert(test_out_of_bounds(std::strided_slice{1, 6, 2}));  // { dg-error 
"expansion of" }
+static_assert(test_out_of_bounds(std::strided_slice{1, 4, 2}));  // { dg-error 
"expansion of" }
 static_assert(test_out_of_bounds(std::tuple{1, 6}));             // { dg-error 
"expansion of" }
 static_assert(test_out_of_bounds(std::tuple{std::cw<1>, std::cw<6>})); // { 
dg-error "expansion of" }
 static_assert(test_out_of_bounds(std::strided_slice{-1, 2, 1})); // { dg-error 
"expansion of" }
diff --git 
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc
index 39eb18cb03df..74fccc6f014b 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc
@@ -75,7 +75,7 @@ template<typename Layout>
   constexpr bool
   test_strided_slice_zero()
   {
-    check_slice_range<Layout>(1, std::strided_slice{1, 1, 0}, 2);  // { 
dg-error "expansion of" }
+    check_slice_range<Layout>(1, std::strided_slice{1, 2, 0}, 2);  // { 
dg-error "expansion of" }
     return true;
   }
 static_assert(test_strided_slice_zero<std::layout_left>());   // { dg-error 
"expansion of" }

Reply via email to