+ 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));
+ }
+
+ template<size_t _Index, typename _Extents>
+ constexpr auto
+ __extract_extent(const _Extents& __exts)
+ {
+ using _IndexType = typename _Extents::index_type;
+ return extents<_IndexType, _Extents::static_extent(_Index)>{
+ __exts.extent(_Index)};
+ }
+
+ template<typename _Extents, typename... _Slices>
+ constexpr void
+ __assert_valid_slices(const _Extents& __exts, const _Slices&...
__slices)
+ {
+ constexpr auto __rank = _Extents::rank();
+ auto __impl = [&]<size_t... _Is>(index_sequence<_Is...>)
+ {
+ ((__assert_valid_slice(__extract_extent<_Is>(__exts),
+ __slices...[_Is])),...);
+ };
+ __impl(make_index_sequence<__rank>());
+ }
+#endif // __glibcxx_submdspan
}
template<typename _Extents>
class layout_left::mapping
{
public:
using extents_type = _Extents;
using index_type = typename extents_type::index_type;
using size_type = typename extents_type::size_type;
using rank_type = typename extents_type::rank_type;
@@ -2492,14 +2677,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
-> mdspan<_ElementType, typename _MappingType::extents_type,
typename _MappingType::layout_type>;
template<typename _MappingType, typename _AccessorType>
mdspan(const typename _AccessorType::data_handle_type&, const
_MappingType&,
const _AccessorType&)
-> mdspan<typename _AccessorType::element_type,
typename _MappingType::extents_type,
typename _MappingType::layout_type, _AccessorType>;
+#if __glibcxx_submdspan
+ template<typename _IndexType, size_t... _Extents, typename... _Slices>
+ requires (sizeof...(_Extents) == sizeof...(_Slices))
+ constexpr auto
+ submdspan_canonicalize_slices(const extents<_IndexType, _Extents...>&
__exts,
+ _Slices... __raw_slices)
+ {
+ auto [...__slices]
+ = make_tuple(__mdspan::__slice_cast<_IndexType>(__raw_slices)...);
+ __mdspan::__assert_valid_slices(__exts, __slices...);
+ return make_tuple(__slices...);
+ }
+#endif // __glibcxx_submdspan
+
_GLIBCXX_END_NAMESPACE_VERSION
}
#endif
#endif
diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/
std.cc.in
index dd458a230e6..63b3d183bf5 100644
--- a/libstdc++-v3/src/c++23/std.cc.in
+++ b/libstdc++-v3/src/c++23/std.cc.in
@@ -1874,20 +1874,21 @@ export namespace std
using std::aligned_accessor;
#endif
using std::mdspan;
#if __glibcxx_padded_layouts
using std::layout_left_padded;
using std::layout_right_padded;
using std::strided_slice;
using std::full_extent_t;
using std::full_extent;
using std::submdspan_mapping_result;
+ using std::submdspan_canonicalize_slices;
#endif
// FIXME submdspan_extents, mdsubspan
}
#endif
// 20.2 <memory>
export namespace std
{
using std::align;
using std::allocator;
diff --git
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices.cc
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices.cc
new file mode 100644
index 00000000000..1dec3548c1d
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices.cc
@@ -0,0 +1,212 @@
+// { dg-do run { target c++26 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+#include <cstddef>
+#include <cstdint>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+template<typename Extents, typename CInt>
+ constexpr bool
+ check_collapsing(Extents exts, CInt ci_raw)
+ {
+ using IndexType = typename Extents::index_type;
+ auto ci_expected = std::cw<IndexType{ci_raw.value}>;
+ auto [ci] = std::submdspan_canonicalize_slices(exts, ci_raw);
+ static_assert(std::same_as<decltype(ci), decltype(ci_expected)>);
+ VERIFY(std::cmp_equal(ci.value, ci_raw.value));
+
+ auto [i] = std::submdspan_canonicalize_slices(exts, ci_raw.value);
+ static_assert(std::same_as<decltype(i), IndexType>);
+ VERIFY(std::cmp_equal(i, ci_raw.value));
+ return true;
+ }
+
+template<typename Extents>
+ constexpr bool
+ test_scalar(Extents exts)
+ {
+ using IndexType = typename Extents::index_type;
+
+ check_collapsing(exts, std::cw<uint8_t{0}>);
+ check_collapsing(exts, std::cw<IndexType{0}>);
+
+ check_collapsing(exts, std::cw<uint8_t{4}>);
+ check_collapsing(exts, std::cw<IndexType{4}>);
+ return true;
+ }
+
+constexpr bool
+test_scalar()
+{
+ test_scalar(std::extents<int, dyn>{5});
+ test_scalar(std::extents<int, 5>{});
+ test_scalar(std::extents<unsigned int, dyn>{5});
+ test_scalar(std::extents<unsigned int, 5>{});
+ return true;
+}
+
+constexpr void
+assert_same(auto lhs, auto rhs)
+{
+ static_assert(std::same_as<decltype(lhs), decltype(rhs)>);
+ VERIFY(lhs == rhs);
+}
+
+template<template<typename, typename> typename Pair>
+ constexpr bool
+ test_pair(auto exts, auto cbegin, auto cend, auto coffset, auto cextent)
+ {
+ using IndexType = typename decltype(exts)::index_type;
+ auto c1 = std::cw<IndexType{1}>;
+
+ auto raw_cc = Pair{cbegin, cend};
+ auto [cc] = std::submdspan_canonicalize_slices(exts, raw_cc);
+ assert_same(cc.offset, coffset);
+ assert_same(cc.extent, cextent);
+ assert_same(cc.stride, c1);
+
+ auto raw_cd = Pair{cbegin, cend.value};
+ auto [cd] = std::submdspan_canonicalize_slices(exts, raw_cd);
+ assert_same(cd.offset, coffset);
+ assert_same(cd.extent, cextent.value);
+ assert_same(cd.stride, c1);
+
+ auto raw_dc = Pair{cbegin.value, cend};
+ auto [dc] = std::submdspan_canonicalize_slices(exts, raw_dc);
+ assert_same(dc.offset, coffset.value);
+ assert_same(dc.extent, cextent.value);
+ assert_same(dc.stride, c1);
+
+ auto raw_dd = Pair{cbegin.value, cend.value};
+ auto [dd] = std::submdspan_canonicalize_slices(exts, raw_dd);
+ assert_same(dd.offset, coffset.value);
+ assert_same(dd.extent, cextent.value);
+ assert_same(dd.stride, c1);
+ return true;
+ }
+
+template<template<typename, typename> typename Pair>
+ constexpr bool
+ test_pair()
+ {
+ test_pair<Pair>(std::extents<int, dyn>{5}, std::cw<uint8_t{2}>,
+ std::cw<uint8_t{5}>, std::cw<2>, std::cw<3>);
+ test_pair<Pair>(std::extents<int, 5>{}, std::cw<uint8_t{2}>,
+ std::cw<uint8_t{5}>, std::cw<2>, std::cw<3>);
+ test_pair<Pair>(std::extents<int, 0>{}, std::cw<uint8_t{0}>,
+ std::cw<uint8_t{0}>, std::cw<0>, std::cw<0>);
+ test_pair<Pair>(std::extents<int, dyn>{0}, std::cw<uint8_t{0}>,
+ std::cw<uint8_t{0}>, std::cw<0>, std::cw<0>);
+ return true;
+ }
+
+constexpr bool
+test_pair_all()
+{
+ test_pair<std::pair>();
+ test_pair<std::tuple>();
+ return true;
+}
+
+constexpr bool
+test_strided_slice(auto exts, auto co, auto ce, auto cs)
+{
+ 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::submdspan_canonicalize_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::submdspan_canonicalize_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::submdspan_canonicalize_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::submdspan_canonicalize_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()
+{
+ auto run = [](auto exts)
+ {
+ 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);
+ };
+
+ run(std::extents<int, 5>{});
+ run(std::extents<int, dyn>{5});
+ return true;
+}
+
+constexpr bool
+test_strided_slice_zero_extent(auto exts, auto cs)
+{
+ 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::submdspan_canonicalize_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::submdspan_canonicalize_slices(exts, raw_ccd);
+ assert_same(ccd.stride, std::cw<IndexType{1}>);
+ return true;
+}
+
+constexpr bool
+test_strided_slice_zero_extent(auto exts)
+{
+ test_strided_slice_zero_extent(exts, std::cw<uint8_t{0}>);
+ test_strided_slice_zero_extent(exts, std::cw<uint8_t{9}>);
+ return true;
+}
+
+constexpr bool
+test_strided_slice_zero_extent()
+{
+ 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});
+ return true;
+}
+
+constexpr bool
+test_all()
+{
+ test_scalar();
+ test_pair_all();
+ test_strided_slice();
+ test_strided_slice_zero_extent();
+ return true;
+}
+
+int
+main()
+{
+ test_all();
+ static_assert(test_all());
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc
new file mode 100644
index 00000000000..94bca183aa3
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc
@@ -0,0 +1,208 @@
+// { dg-do compile { target c++26 } }
+#include <mdspan>
+
+#include <cstdint>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+constexpr auto dyn_empty = std::extents<int32_t, dyn>{0};
+constexpr auto sta_empty = std::extents<uint32_t, 0>{};
+
+constexpr auto dyn_uexts = std::extents<uint8_t, dyn>{5};
+constexpr auto sta_uexts = std::extents<uint16_t, 5>{5};
+constexpr auto dyn_sexts = std::extents<int8_t, dyn>{5};
+constexpr auto sta_sexts = std::extents<int16_t, 5>{5};
+
+constexpr bool
+test_rank_mismatch()
+{
+ auto exts = std::extents(1);
+ std::submdspan_canonicalize_slices(exts, 0, 0); // { dg-error "no
matching" }
+ return true;
+}
+
+template<typename Int, typename Extents>
+constexpr bool
+test_under1(Int i1, Extents exts)
+{
+ auto [s1] = std::submdspan_canonicalize_slices(exts, i1);
+ return true;
+}
+
+static_assert(test_under1(-1, dyn_sexts)); // { dg-error "expansion of"
}
+static_assert(test_under1(-1, dyn_uexts)); // { dg-error "expansion of"
}
+static_assert(test_under1(-1, sta_sexts)); // { dg-error "expansion of"
}
+static_assert(test_under1(-1, sta_uexts)); // { dg-error "expansion of"
}
+
+static_assert(test_under1(std::cw<-1>, dyn_sexts)); // { dg-error
"required from" }
+static_assert(test_under1(std::cw<-1>, dyn_uexts)); // { dg-error
"required from" }
+static_assert(test_under1(std::cw<-1>, sta_sexts)); // { dg-error
"required from" }
+static_assert(test_under1(std::cw<-1>, sta_uexts)); // { dg-error
"required from" }
+
+template<typename Int, typename Extents>
+constexpr bool
+test_over1(Int i1, Extents exts)
+{
+ auto [s1] = std::submdspan_canonicalize_slices(exts, i1);
+ return true;
+}
+
+static_assert(test_over1(0, dyn_empty)); // { dg-error "expansion of" }
+static_assert(test_over1(0, sta_empty)); // { dg-error "expansion of" }
+static_assert(test_over1(5, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over1(5, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over1(5, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over1(5, sta_uexts)); // { dg-error "expansion of" }
+
+static_assert(test_over1(std::cw<0>, dyn_empty)); // { dg-error
"expansion of" }
+static_assert(test_over1(std::cw<0>, sta_empty)); // { dg-error
"expansion of" }
+static_assert(test_over1(std::cw<5>, dyn_sexts)); // { dg-error
"expansion of" }
+static_assert(test_over1(std::cw<5>, dyn_uexts)); // { dg-error
"expansion of" }
+static_assert(test_over1(std::cw<5>, sta_sexts)); // { dg-error
"expansion of" }
+static_assert(test_over1(std::cw<5>, sta_uexts)); // { dg-error
"expansion of" }
+
+template<typename Offset, typename Extent, typename Stride, typename
Extents>
+ constexpr bool
+ test_under2(Offset o, Extent e, Stride s, Extents exts)
+ {
+ std::submdspan_canonicalize_slices(exts, std::strided_slice{o, e, s});
+ return true;
+ }
+
+constexpr auto i8_1 = int8_t{1};
+
+static_assert(test_under2(-i8_1, 0, 1, dyn_uexts)); // { dg-error
"expansion of" }
+static_assert(test_under2(0, -i8_1, 1, dyn_uexts)); // { dg-error
"expansion of" }
+static_assert(test_under2(0, 1, -i8_1, dyn_uexts)); // { dg-error
"expansion of" }
+static_assert(test_under2(-i8_1, 0, 1, dyn_sexts)); // { dg-error
"expansion of" }
+static_assert(test_under2(0, -i8_1, 1, dyn_sexts)); // { dg-error
"expansion of" }
+static_assert(test_under2(0, 1, -i8_1, dyn_sexts)); // { dg-error
"expansion of" }
+static_assert(test_under2(-i8_1, 0, 1, sta_uexts)); // { dg-error
"expansion of" }
+static_assert(test_under2(0, -i8_1, 1, sta_uexts)); // { dg-error
"expansion of" }
+static_assert(test_under2(0, 1, -i8_1, sta_uexts)); // { dg-error
"expansion of" }
+static_assert(test_under2(-i8_1, 0, 1, sta_sexts)); // { dg-error
"expansion of" }
+static_assert(test_under2(0, -i8_1, 1, sta_sexts)); // { dg-error
"expansion of" }
+static_assert(test_under2(0, 1, -i8_1, sta_sexts)); // { dg-error
"expansion of" }
+
+constexpr auto c_i8_m1 = std::cw<int8_t{-1}>;
+constexpr auto c_i16_m1 = std::cw<int16_t{-1}>;
+constexpr auto c_i64_m1 = std::cw<int64_t{-1}>;
+
+static_assert(test_under2(c_i8_m1, 0, 1, dyn_uexts)); // { dg-error
"required from" }
+static_assert(test_under2(0, c_i16_m1, 1, dyn_uexts)); // { dg-error
"required from" }
+static_assert(test_under2(0, 1, c_i64_m1, dyn_uexts)); // { dg-error
"required from" }
+static_assert(test_under2(c_i8_m1, 0, 1, dyn_sexts)); // { dg-error
"required from" }
+static_assert(test_under2(0, c_i16_m1, 1, dyn_sexts)); // { dg-error
"required from" }
+static_assert(test_under2(0, 1, c_i64_m1, dyn_sexts)); // { dg-error
"required from" }
+static_assert(test_under2(c_i8_m1, 0, 1, sta_uexts)); // { dg-error
"required from" }
+static_assert(test_under2(0, c_i16_m1, 1, sta_uexts)); // { dg-error
"required from" }
+static_assert(test_under2(0, 1, c_i64_m1, sta_uexts)); // { dg-error
"required from" }
+static_assert(test_under2(c_i8_m1, 0, 1, sta_sexts)); // { dg-error
"required from" }
+static_assert(test_under2(0, c_i16_m1, 1, sta_sexts)); // { dg-error
"required from" }
+static_assert(test_under2(0, 1, c_i64_m1, sta_sexts)); // { dg-error
"required from" }
+
+template<typename Offset, typename Extent, typename Stride, typename
Extents>
+ constexpr bool
+ test_over2(Offset o, Extent e, Stride s, Extents exts)
+ {
+ std::submdspan_canonicalize_slices(exts, std::strided_slice{o, e, s});
+ return true;
+ }
+
+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 c4 = std::cw<4>;
+
+static_assert(test_over2(i8_6, 0, 1, dyn_uexts)); // { dg-error
"expansion of" }
+static_assert(test_over2(0, i8_6, 1, dyn_uexts)); // { dg-error
"expansion of" }
+static_assert(test_over2(2, 4, 0, dyn_uexts)); // { dg-error
"expansion of" }
+static_assert(test_over2(c_i8_6, 0, 1, dyn_uexts)); // { dg-error
"expansion of" }
+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(i8_6, 0, 1, dyn_sexts)); // { dg-error
"expansion of" }
+static_assert(test_over2(0, i8_6, 1, dyn_sexts)); // { dg-error
"expansion of" }
+static_assert(test_over2(2, 4, 0, dyn_sexts)); // { dg-error
"expansion of" }
+static_assert(test_over2(c_i8_6, 0, 1, dyn_sexts)); // { dg-error
"expansion of" }
+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(i8_6, 0, 1, sta_uexts)); // { dg-error
"expansion of" }
+static_assert(test_over2(0, i8_6, 1, sta_uexts)); // { dg-error
"expansion of" }
+static_assert(test_over2(2, 4, 0, sta_uexts)); // { dg-error
"expansion of" }
+static_assert(test_over2(c_i8_6, 0, 1, sta_uexts)); // { dg-error
"expansion of" }
+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(i8_6, 0, 1, sta_sexts)); // { dg-error
"expansion of" }
+static_assert(test_over2(0, i8_6, 1, sta_sexts)); // { dg-error
"expansion of" }
+static_assert(test_over2(2, 4, 0, sta_sexts)); // { dg-error
"expansion of" }
+static_assert(test_over2(c_i8_6, 0, 1, sta_sexts)); // { dg-error
"expansion of" }
+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" }
+
+// Checks the precondition: offset + extent <= exts.extent(0) for unsigned
+// index_type when offset + extent overflows.
+constexpr bool
+test_overflow1(auto o, auto e)
+{
+ auto exts = std::extents<uint8_t, dyn>{255};
+ auto slice = std::strided_slice{o, e, 1};
+ std::submdspan_canonicalize_slices(exts, slice);
+ return true;
+}
+
+static_assert(test_overflow1(128, 128)); // { dg-error
"expansion of" }
+static_assert(test_overflow1(std::cw<128>, 128)); // { dg-error
"expansion of" }
+static_assert(test_overflow1(128, std::cw<128>)); // { dg-error
"expansion of" }
+static_assert(test_overflow1(std::cw<128>, std::cw<128>)); // { dg-error
"expansion of" }
+
+constexpr bool
+test_overflow2(auto b, auto e)
+{
+ auto exts = std::extents<uint8_t, dyn>{255};
+ auto slice = std::pair{b, e};
+ std::submdspan_canonicalize_slices(exts, slice);
+ return true;
+}
+
+static_assert(test_overflow2(5, 4)); // { dg-error
"expansion of" }
+static_assert(test_overflow2(std::cw<5>, 4)); // { dg-error
"expansion of" }
+static_assert(test_overflow2(5, std::cw<4>)); // { dg-error
"expansion of" }
+static_assert(test_overflow2(std::cw<5>, std::cw<4>)); // { dg-error
"expansion of" }
+
+constexpr auto u8_4 = uint8_t{4};
+constexpr auto u8_5 = uint8_t{5};
+static_assert(test_overflow2(u8_5, u8_4)); // {
dg-error "expansion of" }
+static_assert(test_overflow2(std::cw<u8_5>, u8_4)); // {
dg-error "expansion of" }
+static_assert(test_overflow2(u8_5, std::cw<u8_4>)); // {
dg-error "expansion of" }
+static_assert(test_overflow2(std::cw<u8_5>, std::cw<u8_4>)); // {
dg-error "expansion of" }
+
+constexpr bool
+test_invalid(auto e, auto s)
+{
+ auto exts = std::extents(5);
+ auto slice = std::strided_slice(0, e, s);
+ std::submdspan_canonicalize_slices(exts, slice);
+ return true;
+}
+
+static_assert(test_invalid(3, 0)); // { dg-error
"expansion of" }
+static_assert(test_invalid(3, std::cw<0>)); // { dg-error
"expansion of" }
+static_assert(test_invalid(3, std::cw<0>)); // { dg-error
"expansion of" }
+static_assert(test_invalid(std::cw<3>, std::cw<0>)); // { dg-error
"expansion of" }
+
+
+// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "__glibcxx_assert_fail" }
+// { dg-prune-output "__glibcxx_assert" }
+// { dg-prune-output "non-constant condition" }
--
2.51.2