On Wed, 9 Apr 2025 at 08:30, Luc Grosheintz <luc.groshei...@gmail.com> wrote: > > A prior commit added std::extents, this commits adds the tests. The bulk > is focussed on testing the constructors. These are split into three > groups: > > 1. the ctor from other extents and the copy ctor, > 2. the ctor from a pack of integer-like objects, > 3. the ctor from shapes, i.e. span and array. > > For each group check that the ctor: > * produces an object with the expected values for extent, > * is implicit if and only if required, > * is constexpr, > * doesn't change the rank of the extent. > > libstdc++-v3/ChangeLog: > > * testsuite/23_containers/mdspan/extents/assign_copy.cc: New test. > * testsuite/23_containers/mdspan/extents/assign_copy_01_neg.cc: New > test. > * testsuite/23_containers/mdspan/extents/class_traits.cc: New test. > * testsuite/23_containers/mdspan/extents/ctor_copy.cc: New test. > * testsuite/23_containers/mdspan/extents/ctor_copy_01_neg.cc: New > test. > * testsuite/23_containers/mdspan/extents/ctor_copy_02_neg.cc: New > test. > * testsuite/23_containers/mdspan/extents/ctor_copy_constexpr.cc: New > test. > * testsuite/23_containers/mdspan/extents/ctor_copy_implicit_00.cc: > New test. > * testsuite/23_containers/mdspan/extents/ctor_copy_implicit_01.cc: > New test. > * > testsuite/23_containers/mdspan/extents/ctor_copy_implicit_02_neg.cc: New test. > * > testsuite/23_containers/mdspan/extents/ctor_copy_implicit_03_neg.cc: New test. > * > testsuite/23_containers/mdspan/extents/ctor_copy_implicit_04_neg.cc: New test. > * testsuite/23_containers/mdspan/extents/ctor_ints_00.cc: New test. > * testsuite/23_containers/mdspan/extents/ctor_ints_01.cc: New test. > * testsuite/23_containers/mdspan/extents/ctor_ints_02_neg.cc: New > test. > * testsuite/23_containers/mdspan/extents/ctor_ints_03_neg.cc: New > test. > * testsuite/23_containers/mdspan/extents/ctor_ints_constexpr.cc: New > test. > * > testsuite/23_containers/mdspan/extents/ctor_ints_implicit_00_neg.cc: New test. > * > testsuite/23_containers/mdspan/extents/ctor_ints_implicit_01_neg.cc: New test. > * testsuite/23_containers/mdspan/extents/ctor_shape_00.cc: New test. > * testsuite/23_containers/mdspan/extents/ctor_shape_01.cc: New test. > * testsuite/23_containers/mdspan/extents/ctor_shape_02_neg.cc: New > test. > * testsuite/23_containers/mdspan/extents/ctor_shape_03_neg.cc: New > test. > * testsuite/23_containers/mdspan/extents/ctor_shape_constexpr.cc: New > test. > * testsuite/23_containers/mdspan/extents/ctor_shape_implicit_00.cc: > New test. > * testsuite/23_containers/mdspan/extents/ctor_shape_implicit_01.cc: > New test. > * > testsuite/23_containers/mdspan/extents/ctor_shape_implicit_02_neg.cc: New > test. > * > testsuite/23_containers/mdspan/extents/ctor_shape_implicit_03_neg.cc: New > test. > * testsuite/23_containers/mdspan/extents/ctor_shape_implicit_04.cc: > New test. > * testsuite/23_containers/mdspan/extents/custom_integer.cc: New test. > * testsuite/23_containers/mdspan/extents/deduction_guide_00.cc: New > test. > * testsuite/23_containers/mdspan/extents/deduction_guide_01_neg.cc: > New test. > * testsuite/23_containers/mdspan/extents/dextents.cc: New test. > * testsuite/23_containers/mdspan/extents/extent.cc: New test. > * testsuite/23_containers/mdspan/extents/index_type.cc: New test. > * testsuite/23_containers/mdspan/extents/ops_eq.cc: New test. > * testsuite/23_containers/mdspan/extents/rank.cc: New test. > * testsuite/23_containers/mdspan/extents/rank_dynamic.cc: New test. > * testsuite/23_containers/mdspan/extents/rank_return_type.cc: New > test. > * testsuite/23_containers/mdspan/extents/rank_type.cc: New test. > * testsuite/23_containers/mdspan/extents/size_type.cc: New test. > * testsuite/23_containers/mdspan/extents/sizeof.cc: New test. > * testsuite/23_containers/mdspan/extents/static_extent.cc: New test. > > Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com> > --- > .../mdspan/extents/assign_copy.cc | 26 ++++++ > .../mdspan/extents/assign_copy_01_neg.cc | 15 ++++ > .../mdspan/extents/class_traits.cc | 20 +++++ > .../23_containers/mdspan/extents/ctor_copy.cc | 34 ++++++++ > .../mdspan/extents/ctor_copy_01_neg.cc | 10 +++ > .../mdspan/extents/ctor_copy_02_neg.cc | 10 +++ > .../mdspan/extents/ctor_copy_constexpr.cc | 20 +++++ > .../mdspan/extents/ctor_copy_implicit_00.cc | 28 ++++++ > .../mdspan/extents/ctor_copy_implicit_01.cc | 22 +++++ > .../extents/ctor_copy_implicit_02_neg.cc | 10 +++ > .../extents/ctor_copy_implicit_03_neg.cc | 9 ++ > .../extents/ctor_copy_implicit_04_neg.cc | 9 ++ > .../mdspan/extents/ctor_ints_00.cc | 30 +++++++ > .../mdspan/extents/ctor_ints_01.cc | 24 ++++++ > .../mdspan/extents/ctor_ints_02_neg.cc | 9 ++ > .../mdspan/extents/ctor_ints_03_neg.cc | 9 ++ > .../mdspan/extents/ctor_ints_constexpr.cc | 12 +++ > .../extents/ctor_ints_implicit_00_neg.cc | 9 ++ > .../extents/ctor_ints_implicit_01_neg.cc | 9 ++ > .../mdspan/extents/ctor_shape_00.cc | 35 ++++++++ > .../mdspan/extents/ctor_shape_01.cc | 17 ++++ > .../mdspan/extents/ctor_shape_02_neg.cc | 10 +++ > .../mdspan/extents/ctor_shape_03_neg.cc | 11 +++ > .../mdspan/extents/ctor_shape_constexpr.cc | 23 +++++ > .../mdspan/extents/ctor_shape_implicit_00.cc | 42 +++++++++ > .../mdspan/extents/ctor_shape_implicit_01.cc | 19 ++++ > .../extents/ctor_shape_implicit_02_neg.cc | 11 +++ > .../extents/ctor_shape_implicit_03_neg.cc | 12 +++ > .../mdspan/extents/ctor_shape_implicit_04.cc | 24 ++++++ > .../mdspan/extents/custom_integer.cc | 86 +++++++++++++++++++ > .../mdspan/extents/deduction_guide_00.cc | 23 +++++ > .../mdspan/extents/deduction_guide_01_neg.cc | 10 +++ > .../23_containers/mdspan/extents/dextents.cc | 11 +++ > .../23_containers/mdspan/extents/extent.cc | 27 ++++++ > .../mdspan/extents/index_type.cc | 14 +++ > .../23_containers/mdspan/extents/ops_eq.cc | 58 +++++++++++++ > .../23_containers/mdspan/extents/rank.cc | 10 +++ > .../mdspan/extents/rank_dynamic.cc | 11 +++ > .../mdspan/extents/rank_return_type.cc | 14 +++ > .../23_containers/mdspan/extents/rank_type.cc | 7 ++ > .../23_containers/mdspan/extents/size_type.cc | 16 ++++ > .../23_containers/mdspan/extents/sizeof.cc | 10 +++ > .../mdspan/extents/static_extent.cc | 15 ++++ > 43 files changed, 831 insertions(+) > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/assign_copy.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/assign_copy_01_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/class_traits.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_01_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_02_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_constexpr.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_00.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_01.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_02_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_03_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_04_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_00.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_01.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_02_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_03_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_constexpr.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_implicit_00_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_implicit_01_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_00.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_01.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_02_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_03_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_constexpr.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_00.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_01.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_02_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_03_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_04.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/deduction_guide_00.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/deduction_guide_01_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/dextents.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/extent.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/index_type.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ops_eq.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/rank.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/rank_dynamic.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/rank_return_type.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/rank_type.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/size_type.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/sizeof.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/static_extent.cc > > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/assign_copy.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/assign_copy.cc > new file mode 100644 > index 00000000000..ba7e495a817 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/assign_copy.cc > @@ -0,0 +1,26 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +constexpr auto dyn = std::dynamic_extent; > + > +int > +main() > +{ > + auto e1 = std::extents<int, 1, 2>(); > + auto e2 = std::extents<int, 1, 2>(); > + > + e2 = e1; > + VERIFY(e2 == e1); > + > + auto e5 = std::extents<int, 1, dyn>(); > + e5 = e1; > + VERIFY(e5 == e1); > + > + auto e3 = std::extents<int, dyn, dyn>(1, 2); > + auto e4 = std::extents<int, dyn, dyn>(3, 4); > + e3 = e4; > + VERIFY(e3 == e4); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/assign_copy_01_neg.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/assign_copy_01_neg.cc > new file mode 100644 > index 00000000000..8a514f2207b > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/assign_copy_01_neg.cc > @@ -0,0 +1,15 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +constexpr auto dyn = std::dynamic_extent; > + > +void > +test_assigment() > +{ > + auto e1 = std::extents<int, 1, 2>(); > + auto e2 = std::extents<int, 1, dyn>(); > + > + e1 = e2; > +} > + > +// { dg-error "no match for 'operator=" "" { target *-*-* } 12 }
Could most of these negative *_neg.cc tests be replaced by checks like static_assert( ! std::is_copy_assignable_v<...> ) in the corresponding positive test, e.g. assign_copy.cc in this case? Every separate test file has a small but measurable startup cost for the testsuite, and we already have 10k test files! If we can verify the same behaviour using concepts or traits, we don't need a separate neg.cc test. Sometimes we really do want a separate test, because we want to check that there's a specific error message, or we want to check for a static_assert inside a function body which can't be checked using concepts and so really does need to use dg-error, but I don't think that appies here. The string you're matching is just the generic "no match" error from the compiler. > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_traits.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_traits.cc > new file mode 100644 > index 00000000000..ae6ea988a1a > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_traits.cc > @@ -0,0 +1,20 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +#include <type_traits> > + > +template <std::regular T> > + struct is_regular > + { > + static constexpr bool value = true; > + }; > + > +constexpr auto dyn = std::dynamic_extent; > + > +static_assert(is_regular<std::extents<int>>::value); > +static_assert(is_regular<std::extents<int, 1>>::value); > +static_assert(is_regular<std::extents<int, dyn>>::value); > + > +static_assert(std::is_trivially_copyable_v<std::extents<int>>); > +static_assert(std::is_trivially_copyable_v<std::extents<int, 1>>); > +static_assert(std::is_trivially_copyable_v<std::extents<int, dyn>>); > diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc > new file mode 100644 > index 00000000000..02cd1444e3f > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc > @@ -0,0 +1,34 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +// Test that ctor from other extents creates an object from that's equal to > the > +// original. > + > +constexpr auto dyn = std::dynamic_extent; > + > +template<class T, size_t ... Extents, class Other> > + void > + test_copy_ctor_explicit(const Other& other) > + { > + auto e = std::extents<T, Extents...>(other); > + VERIFY(e == other); > + } > + > +int > +main() > +{ > + auto e0 = std::extents<int>(); > + test_copy_ctor_explicit<int>(e0); > + > + auto e1 = std::extents<int, 1, 2, 3>(); > + test_copy_ctor_explicit<int, 1, 2, 3>(e1); > + test_copy_ctor_explicit<int, 1, dyn, 3>(e1); > + > + auto e2 = std::extents<int, 1, dyn, 3>{1, 2, 3}; > + test_copy_ctor_explicit<int, 1, 2, 3>(e2); > + test_copy_ctor_explicit<int, 1, dyn, 3>(e2); > + test_copy_ctor_explicit<int, 1, dyn, dyn>(e2); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_01_neg.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_01_neg.cc > new file mode 100644 > index 00000000000..8a859924e6a > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_01_neg.cc > @@ -0,0 +1,10 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +// Check Self::rank != Other::rank > + > +constexpr auto dyn = std::dynamic_extent; > +std::extents<int, 1, dyn> e1; > +std::extents<int, 1, dyn, 3> e2(e1); > + > +// { dg-error "no matching function for call" "" { target *-*-* } 8 } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_02_neg.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_02_neg.cc > new file mode 100644 > index 00000000000..51fab74ccbd > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_02_neg.cc > @@ -0,0 +1,10 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +// Check when static extents differ. > + > +constexpr auto dyn = std::dynamic_extent; > +std::extents<int, 1, dyn> e1; > +std::extents<int, 2, dyn> e2(e1); > + > +// { dg-error "no matching function for call" "" { target *-*-* } 8 } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_constexpr.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_constexpr.cc > new file mode 100644 > index 00000000000..49fa023c354 > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_constexpr.cc > @@ -0,0 +1,20 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +// Test that the ctor from other extents is constexpr. > + > +constexpr auto dyn = std::dynamic_extent; > + > +constexpr std::extents<int> e0; > +constexpr std::extents<int> e1 = e0; > + > +constexpr std::extents<int, 1> e2; > +constexpr std::extents<int, 1> e3 = e2; > +static_assert(e3 == e2); > + > +constexpr std::extents<int, dyn> e4 = e2; > +static_assert(e4 == e2); > + > +constexpr std::extents<int, 3, 5> e5; > +constexpr std::extents<int, dyn, 5> e6 = e5; > +static_assert(e6 == e5); > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_00.cc > > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_00.cc > new file mode 100644 > index 00000000000..1c8b0b9f011 > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_00.cc > @@ -0,0 +1,28 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +// Test that implicit conversion is permitted if the extents can't be > +// incompatible. > +int > +main() > +{ > + constexpr auto dyn = std::dynamic_extent; > + > + auto e1 = std::extents<int, 1, 2, 3>(); > + std::extents<int, 1, 2, 3> e2 = e1; > + VERIFY(e1 == e2); > + > + auto shape = std::array<int, 3>{1, 2, 3}; > + auto e3 = std::extents<int, 1, dyn, 3>(shape); > + std::extents<int, 1, dyn, 3> e4 = e3; > + VERIFY(e4 == e3); > + > + std::extents<int, 1, dyn, dyn> e5 = e3; > + VERIFY(e5 == e3); > + > + std::extents<unsigned int, 1, dyn, 3> e6 = e1; > + VERIFY(e6 == e1); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_01.cc > > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_01.cc > new file mode 100644 > index 00000000000..13c082be729 > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_01.cc > @@ -0,0 +1,22 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +// Test that implicit conversion is permitted if overflow isn't possible. > +int > +main() > +{ > + constexpr auto dyn = std::dynamic_extent; > + > + auto e0 = std::extents<int>(); > + std::extents<unsigned int> e1 = e0; > + > + auto e3 = std::extents<int, 1, 2, 3>(); > + std::extents<unsigned int, 1, 2, 3> e4 = e3; > + VERIFY(e4 == e3); > + > + std::extents<unsigned int, 1, dyn, 3> e5 = e3; > + VERIFY(e5 == e3); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_02_neg.cc > > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_02_neg.cc > new file mode 100644 > index 00000000000..ed570f6a10f > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_02_neg.cc > @@ -0,0 +1,10 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +// Implicit conversion must not happen when a static extent in self is > dynamic > +// in other. > + > +constexpr auto e1 = std::extents<int, 1, std::dynamic_extent, 3>(); > +std::extents<int, 1, 2, 3> e2 = e1; > + > +// { dg-error "conversion from 'extents" "" { target *-*-* } 8 } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_03_neg.cc > > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_03_neg.cc > new file mode 100644 > index 00000000000..66b60e38bf1 > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_03_neg.cc > @@ -0,0 +1,9 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +// Implicit conversion must not when overflow is possible. > + > +std::extents<unsigned int, 1, 2, 3> e1; > +std::extents<int, 1, 2, 3> e2 = e1; > + > +// { dg-error "conversion from 'extents" "" { target *-*-* } 7 } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_04_neg.cc > > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_04_neg.cc > new file mode 100644 > index 00000000000..dbf3f7e679a > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_implicit_04_neg.cc > @@ -0,0 +1,9 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +// No implicit conversion because of the IndexType. > + > +std::extents<unsigned int> e1; > +std::extents<int> e2 = e1; > + > +// { dg-error "conversion from 'extents" "" { target *-*-* } 7 } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_00.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_00.cc > new file mode 100644 > index 00000000000..1d7739e6240 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_00.cc > @@ -0,0 +1,30 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +constexpr auto dyn = std::dynamic_extent; > + > +template<class IndexType, size_t ... Extents, class Array> > + void > + test_ctor_ints_00(const std::extents<IndexType, Extents...>& e, > + const Array& shape) > + { > + for(size_t i = 0; i < sizeof...(Extents); ++i) > + VERIFY(e.extent(i) == shape[i]); > + } > + > +int > +main() > +{ > + auto shape = std::array<int, 3>{1, 2, 3}; > + > + test_ctor_ints_00(std::extents<int, 1, 2, 3>(1, 2, 3), shape); > + test_ctor_ints_00(std::extents<int, dyn, 2, 3>(1, 2, 3), shape); > + test_ctor_ints_00(std::extents<int, dyn, 2, dyn>(1, 2, 3), shape); > + > + test_ctor_ints_00(std::extents<int, 1, 2, 3>{1, 2, 3}, shape); > + test_ctor_ints_00(std::extents<int, dyn, 2, 3>{1, 2, 3}, shape); > + test_ctor_ints_00(std::extents<int, dyn, 2, dyn>{1, 2, 3}, shape); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_01.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_01.cc > new file mode 100644 > index 00000000000..86baf5b5800 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_01.cc > @@ -0,0 +1,24 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +constexpr auto dyn = std::dynamic_extent; > + > +template<class Lhs, class Rhs> > + void > + verify(const Lhs& lhs, const Rhs& rhs) > + { VERIFY(lhs == rhs); } > + > +int > +main() > +{ > + auto expected = std::extents<int, 1, 2, 3>(); > + > + verify(std::extents<int, dyn, 2, 3>(1), expected); > + verify(std::extents<int, dyn, 2, dyn>(1, 3), expected); > + > + verify(std::extents<int, dyn, 2, 3>{1}, expected); > + verify(std::extents<int, dyn, 2, dyn>{1, 3}, expected); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_02_neg.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_02_neg.cc > new file mode 100644 > index 00000000000..e8605c1a980 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_02_neg.cc > @@ -0,0 +1,9 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +// Check N != rank && N != rank_dynamic > + > +constexpr auto dyn = std::dynamic_extent; > +std::extents<int, 1, dyn, 3> e1(1, 3); > + > +// { dg-error "no matching function for call" "" { target *-*-* } 7 } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_03_neg.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_03_neg.cc > new file mode 100644 > index 00000000000..9c3ea800283 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_03_neg.cc > @@ -0,0 +1,9 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +// Check N != rank && N != rank_dynamic > + > +constexpr auto dyn = std::dynamic_extent; > +std::extents<int, dyn, dyn> e1(1); > + > +// { dg-error "no matching function for call" "" { target *-*-* } 7 } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_constexpr.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_constexpr.cc > new file mode 100644 > index 00000000000..11f1520c652 > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_constexpr.cc > @@ -0,0 +1,12 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +constexpr auto dyn = std::dynamic_extent; > + > +constexpr auto e0 = std::extents<int, 1, 2>(1, 2); > +constexpr auto e1 = std::extents<int, 1, dyn>(2); > +constexpr auto e3 = std::extents<int, dyn, dyn>(1, 2); > + > +constexpr auto e4 = std::extents<int, 1, 2>{1, 2}; > +constexpr auto e5 = std::extents<int, 1, dyn>{2}; > +constexpr auto e6 = std::extents<int, dyn, dyn>{1, 2}; > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_implicit_00_neg.cc > > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_implicit_00_neg.cc > new file mode 100644 > index 00000000000..d7713fd2bda > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_implicit_00_neg.cc > @@ -0,0 +1,9 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +// Implicit conversion must not happen, via the ctor from > +// int-like objects. > + > +std::extents<int, 1> e = 1; > + > +// { dg-error "conversion from 'int'" "" { target *-*-* } 7 } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_implicit_01_neg.cc > > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_implicit_01_neg.cc > new file mode 100644 > index 00000000000..e18e56b430f > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_implicit_01_neg.cc > @@ -0,0 +1,9 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +// Implicit conversion must not happen, via the ctor from > +// int-like objects. > + > +std::extents<int, std::dynamic_extent> e = 1; > + > +// { dg-error "conversion from 'int'" "" { target *-*-* } 7 } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_00.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_00.cc > new file mode 100644 > index 00000000000..3fd726517fb > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_00.cc > @@ -0,0 +1,35 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +constexpr auto dyn = std::dynamic_extent; > + > +template<typename Lhs, typename Rhs> > + void > + verify(const Lhs& lhs, const Rhs& rhs) > + { VERIFY(lhs == rhs); } > + > +int > +main() > +{ > + auto shape = std::array<int, 3>{1, 2, 3}; > + auto span_const = std::span<const int, 3>(shape); > + auto span = std::span<int, 3>(shape); > + > + auto expected = std::extents<int, 1, 2, 3>(); > + > + verify(std::extents<int, dyn, 2, 3>(shape), expected); > + verify(std::extents<int, 1, dyn, 3>(shape), expected); > + verify(std::extents<int, dyn, dyn, dyn>(shape), expected); > + verify(std::extents<int, 1, 2, 3>(shape), expected); > + > + verify(std::extents<int, 1, dyn, 3>(span_const), expected); > + verify(std::extents<int, dyn, dyn, dyn>(span_const), expected); > + verify(std::extents<int, 1, 2, 3>(span_const), expected); > + > + verify(std::extents<int, 1, dyn, 3>(span), expected); > + verify(std::extents<int, dyn, dyn, dyn>(span), expected); > + verify(std::extents<int, 1, 2, 3>(span), expected); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_01.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_01.cc > new file mode 100644 > index 00000000000..086ad471a72 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_01.cc > @@ -0,0 +1,17 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +constexpr auto dyn = std::dynamic_extent; > + > +int > +main() > +{ > + auto e1 = std::extents<int>(); > + auto e2 = std::extents<unsigned int>(); > + > + VERIFY(e1 == e1); > + VERIFY(e1 == e2); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_02_neg.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_02_neg.cc > new file mode 100644 > index 00000000000..8566cf2eeb2 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_02_neg.cc > @@ -0,0 +1,10 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +// Check N != rank && N != rank_dynamic > + > +auto s = std::array<int, 1>{}; > + > +std::extents<int, 1, 2> e1(s); > + > +// { dg-error "no matching function for call" "" { target *-*-* } 8 } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_03_neg.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_03_neg.cc > new file mode 100644 > index 00000000000..94d75597ae6 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_03_neg.cc > @@ -0,0 +1,11 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +// Check N != rank && N != rank_dynamic > + > +constexpr auto dyn = std::dynamic_extent; > + > +auto s = std::array<int, 1>{}; > +std::extents<int, dyn, dyn> e1(s); > + > +// { dg-error "no matching function for call" "" { target *-*-* } 9 } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_constexpr.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_constexpr.cc > new file mode 100644 > index 00000000000..8abe069c8c6 > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_constexpr.cc > @@ -0,0 +1,23 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +constexpr auto dyn = std::dynamic_extent; > + > +constexpr auto a0 = std::array<int, 0>{}; > +constexpr auto a1 = std::array<int, 1>{2}; > +constexpr auto a2 = std::array<int, 2>{1, 2}; > + > +constexpr auto e0 = std::extents<int, 1, 2>(a0); > +constexpr auto e1 = std::extents<int, 1, dyn>(a1); > +constexpr auto e2 = std::extents<int, 1, 2>(a2); > +constexpr auto e3 = std::extents<int, dyn, dyn>(a2); > + > +constexpr auto s0 = std::span<const int, 0>(a0); > +constexpr auto s1 = std::span<const int, 1>(a1); > +constexpr auto s2 = std::span<const int, 2>(a2); > + > +constexpr auto e4 = std::extents<int, 1, 2>(s0); > +constexpr auto e5 = std::extents<int, 1, dyn>(s1); > +constexpr auto e6 = std::extents<int, 1, 2>(s2); > +constexpr auto e7 = std::extents<int, dyn, dyn>(s2); > + > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_00.cc > > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_00.cc > new file mode 100644 > index 00000000000..427d03d6379 > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_00.cc > @@ -0,0 +1,42 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +// Test construction from an shape (array or span) of exclusively > +// dynamic extents. > + > +constexpr size_t dyn = std::dynamic_extent; > + > +template<class IndexType, size_t ... Extents, class Shape> > + void > + test_ctor_from_dynamic_extents(const Shape& shape) > + { > + std::extents<IndexType, Extents...> e = shape; > + > + VERIFY(e.rank_dynamic() == shape.size()); > + > + size_t di = 0; > + for(size_t i = 0; i < sizeof...(Extents); ++i) > + if(e.static_extent(i) == dyn) > + VERIFY(e.extent(i) == shape[di++]); > + } > + > +int > +main() > +{ > + auto sxxx = std::array<int, 0>{}; > + auto sx2x = std::array<int, 1>{2}; > + auto s123 = std::array<int, 3>{1, 2, 3}; > + > + test_ctor_from_dynamic_extents<int, 1, dyn>(sx2x); > + > + test_ctor_from_dynamic_extents<int, 1, dyn, 3>(sx2x); > + test_ctor_from_dynamic_extents<int, dyn, dyn, dyn>(s123); > + test_ctor_from_dynamic_extents<int, 1, 2, 3>(sxxx); > + > + test_ctor_from_dynamic_extents<int, 1, dyn, 3>(std::span<int, 1>(sx2x)); > + test_ctor_from_dynamic_extents<int, dyn, dyn, dyn>(std::span<int, > 3>(s123)); > + test_ctor_from_dynamic_extents<int, 1, 2, 3>(std::span<int, 0>(sxxx)); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_01.cc > > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_01.cc > new file mode 100644 > index 00000000000..c0d24ea9015 > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_01.cc > @@ -0,0 +1,19 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +// Test implicit conversion for convertible integer types. > + > +constexpr size_t dyn = std::dynamic_extent; > + > +auto a0 = std::array<int, 0>{}; > +std::extents<int> e0 = a0; > +std::extents<unsigned int> e1 = a0; > + > +auto a1 = std::array<int, 1>{2}; > +std::extents<int, 1, dyn, 3> e2 = a1; > +std::extents<unsigned int, 1, dyn, 3> e3 = a1; > + > +auto a2 = std::array<unsigned int, 1>{2}; > +std::extents<int, 1, dyn, 3> e4 = a2; > +std::extents<unsigned int, 1, dyn, 3> e5 = a2; > + > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_02_neg.cc > > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_02_neg.cc > new file mode 100644 > index 00000000000..76cd9d05a8d > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_02_neg.cc > @@ -0,0 +1,11 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > +#include <memory> > + > +// Implicit conversion must not happen when the span contains at least one > +// static extent. > + > +auto s = std::array<int, 3>{1, 2, 3}; > +std::extents<int, 1, std::dynamic_extent, 3> e = s; > + > +// { dg-error "conversion from 'std::array" "" { target *-*-* } 9 } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_03_neg.cc > > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_03_neg.cc > new file mode 100644 > index 00000000000..8bffa799cec > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_03_neg.cc > @@ -0,0 +1,12 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > +#include <memory> > + > +// Implicit conversion must not happen when the span contains at least one > +// static extent. > + > +auto a = std::array<int, 3>{1, 2, 3}; > +auto s = std::span<int, 3>(a); > +std::extents<int, 1, std::dynamic_extent, 3> e = s; > + > +// { dg-error "conversion from 'std::span" "" { target *-*-* } 10 } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_04.cc > > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_04.cc > new file mode 100644 > index 00000000000..4a8da4aaeb7 > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_implicit_04.cc > @@ -0,0 +1,24 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +// Implicit conversion from shapes requires the constraint: convertible and > the > +// pre-condition: non-negative & representable, e.g. the follwing seems to be > +// intended to work. > + > +int > +main() > +{ > + auto a = std::array<double, 1>{2.0}; > + auto s = std::span<double, 1>(a); > + > + std::extents<int, 1, 2> expected; > + > + std::extents<int, 1, std::dynamic_extent> e1 = a; > + VERIFY(e1 == expected); > + > + std::extents<int, 1, std::dynamic_extent> e2 = s; > + VERIFY(e2 == expected); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc > new file mode 100644 > index 00000000000..aae23a73af3 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc > @@ -0,0 +1,86 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +// Test construction from a custom integer-like object, that has > +// no copy/move ctor or copy/move assignment operator. > + > +constexpr size_t dyn = std::dynamic_extent; > + > +class IntLike > +{ > +public: > + IntLike(int i) > + : _M_i(i) > + { } > + > + IntLike() = delete; > + IntLike(const IntLike&) = delete; > + IntLike(IntLike&&) = delete; > + > + const IntLike& > + operator=(const IntLike&) = delete; > + > + const IntLike& > + operator=(IntLike&&) = delete; > + > + constexpr > + operator int() const noexcept > + { return _M_i; } > + > +private: > + int _M_i; > +}; > + > +static_assert(std::is_convertible_v<IntLike, int>); > +static_assert(std::is_nothrow_constructible_v<int, IntLike>); > + > +void > +test_shape(const auto& s2, const auto& s23) > +{ > + std::extents<int, 2, 3> expected; > + > + std::extents<int, 2, 3> e1(s23); > + VERIFY(e1 == expected); > + > + std::extents<int, dyn, 3> e2(s2); > + VERIFY(e2 == expected); > + > + std::extents<int, dyn, 3> e3(s23); > + VERIFY(e3 == expected); > + > + std::extents<int, dyn, dyn> e4(s23); > + VERIFY(e4 == expected); > +} > + > +void > +test_pack() > +{ > + std::extents<int, 2, 3> expected; > + > + std::extents<int, dyn, 3> e1(IntLike(2)); > + VERIFY(e1 == expected); > + > + std::extents<int, dyn, 3> e2(IntLike(2), IntLike(3)); > + VERIFY(e2 == expected); > + > + std::extents<int, dyn, dyn> e3(IntLike(2), IntLike(3)); > + VERIFY(e3 == expected); > +} > + > +int > +main() > +{ > + auto a2 = std::array<IntLike, 1>{2}; > + auto s2 = std::span<IntLike, 1>(a2); > + > + auto a23 = std::array<IntLike, 2>{2, 3}; > + auto s23 = std::span<IntLike, 2>(a23); > + > + test_shape(a2, a23); > + test_shape(s2, s23); > + test_pack(); > + > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/deduction_guide_00.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/deduction_guide_00.cc > new file mode 100644 > index 00000000000..d7f3a51b9f3 > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/deduction_guide_00.cc > @@ -0,0 +1,23 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +#include <type_traits> > + > +constexpr auto dyn = std::dynamic_extent; > + > +constexpr auto e0 = std::extents(); > +static_assert(std::is_same_v<decltype(e0), const std::dextents<size_t, 0>>); > +static_assert(e0 == std::extents<size_t>()); > + > +constexpr auto e1 = std::extents(1); > +static_assert(std::is_same_v<decltype(e1), const std::dextents<size_t, 1>>); > +static_assert(e1 == std::extents<size_t, 1>()); > + > +constexpr auto e2 = std::extents(1.0, 2.0f); > +static_assert(std::is_same_v<decltype(e2), const std::dextents<size_t, 2>>); > +static_assert(e2 == std::extents<size_t, 1, 2>()); > + > +constexpr auto e3 = std::extents(int(1), char(2), size_t(3)); > +static_assert(std::is_same_v<decltype(e3), const std::dextents<size_t, 3>>); > +static_assert(e3 == std::extents<size_t, 1, 2, 3>()); > + > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/deduction_guide_01_neg.cc > > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/deduction_guide_01_neg.cc > new file mode 100644 > index 00000000000..d276634279c > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/deduction_guide_01_neg.cc > @@ -0,0 +1,10 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +struct A > +{ }; > + > +constexpr auto e0 = std::extents(A{}); > + > +// { dg-error "no matching function for call" "" { target *-*-* } 7 } > +// { dg-error "class template argument deduction failed" "" { target *-*-* } > 7 } > diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/dextents.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/dextents.cc > new file mode 100644 > index 00000000000..31544373c72 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/dextents.cc > @@ -0,0 +1,11 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +#include <type_traits> > + > +constexpr auto dyn = std::dynamic_extent; > + > +static_assert(std::is_same_v<std::dextents<int, 0>, std::extents<int>>); > +static_assert(std::is_same_v<std::dextents<int, 1>, std::extents<int, dyn>>); > +static_assert(std::is_same_v<std::dextents<int, 5>, > + std::extents<int, dyn, dyn, dyn, dyn, dyn>>); > diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/extent.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/extent.cc > new file mode 100644 > index 00000000000..41886cabd19 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/extent.cc > @@ -0,0 +1,27 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +constexpr auto dyn = std::dynamic_extent; > + > +template<typename IndexType, size_t... Extents> > + void > + test_extent(const std::extents<IndexType, Extents...>& e) > + { > + VERIFY(e.extent(0) == 1); > + VERIFY(e.extent(1) == 2); > + } > + > +int > +main() > +{ > + auto e1 = std::extents<int, 1, 2>(); > + auto e2 = std::extents<int, 1, dyn>(e1); > + auto e3 = std::extents<int, dyn, dyn>(e1); > + > + test_extent(e1); > + test_extent(e2); > + test_extent(e3); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/index_type.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/index_type.cc > new file mode 100644 > index 00000000000..96c412779ae > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/index_type.cc > @@ -0,0 +1,14 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +#include <type_traits> > + > +template<typename T> > + constexpr bool > + index_type_is_identity() > + { > + return std::is_same_v<typename std::extents<T, 1, 2, 3>::index_type, T>; > + } > + > +static_assert(index_type_is_identity<int>()); > +static_assert(index_type_is_identity<unsigned int>()); > diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ops_eq.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ops_eq.cc > new file mode 100644 > index 00000000000..4a1b0641d9d > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ops_eq.cc > @@ -0,0 +1,58 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +template<class Lhs, class Rhs> > + void > + test_ops_eq(const Lhs& lhs, const Rhs& rhs, bool expected) > + { > + VERIFY((lhs == rhs) == expected); > + VERIFY((lhs != rhs) == !expected); > + } > + > +constexpr auto dyn = std::dynamic_extent; > + > +static_assert(std::extents<int, 1, 2, 3>() == std::extents<int, 1, 2, 3>()); > +static_assert(std::extents<int, 1, 2, 3>() != std::extents<int, 1, 2>()); > +static_assert(std::extents<int, 1, 2, 3>() == std::extents<int, 1, dyn, > 3>(2)); > +static_assert(std::extents<int, 1, 2, 3>() != std::extents<int, 1, dyn, > 3>(3)); > + > +void > +test_rank_zero() > +{ > + auto e1 = std::extents<int>(); > + auto e2 = std::extents<int>(); > + auto e3 = std::extents<unsigned int>(); > + > + test_ops_eq(e1, e2, true); > + test_ops_eq(e1, e3, true); > +} > + > +void > +test_common() > +{ > + auto e1 = std::extents<int, 1, 2, 3>(); > + auto e2 = std::extents<int, 1, 2, 3>(); > + auto e3 = std::extents<int, 1, dyn, 3>(2); > + auto e4 = std::extents<int, 1, dyn, 3>(3); > + > + auto e5 = std::extents<int, 1>(); > + auto e6 = std::extents<int, 1, 3, 3>(); > + > + test_ops_eq(e1, e2, true); > + test_ops_eq(e1, e3, true); > + test_ops_eq(e1, e4, false); > + > + test_ops_eq(e1, e5, false); > + test_ops_eq(e1, e6, false); > + test_ops_eq(e3, e6, false); > +} > + > +int > +main() > +{ > + test_rank_zero(); > + test_common(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/rank.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/rank.cc > new file mode 100644 > index 00000000000..0836a965396 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/rank.cc > @@ -0,0 +1,10 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +constexpr auto dyn = std::dynamic_extent; > + > +static_assert(std::extents<int, 1>::rank() == 1); > +static_assert(std::extents<int, dyn>::rank() == 1); > + > +static_assert(std::extents<int, 2, dyn>::rank() == 2); > + > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/rank_dynamic.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/rank_dynamic.cc > new file mode 100644 > index 00000000000..fc6bbc22618 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/rank_dynamic.cc > @@ -0,0 +1,11 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +constexpr auto dyn = std::dynamic_extent; > + > +static_assert(std::extents<int, 1>::rank_dynamic() == 0); > +static_assert(std::extents<int, dyn>::rank_dynamic() == 1); > + > +static_assert(std::extents<int, 2, dyn>::rank_dynamic() == 1); > +static_assert(std::extents<int, dyn, dyn>::rank_dynamic() == 2); > + > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/rank_return_type.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/rank_return_type.cc > new file mode 100644 > index 00000000000..fef87359256 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/rank_return_type.cc > @@ -0,0 +1,14 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +template<class T, size_t ... Extents> > + constexpr bool > + test_return_type() > + { > + auto e = std::extents<T, Extents...>(); > + return std::is_same_v<decltype(e.rank()), size_t>; > + } > + > +static_assert(test_return_type<int, 1>()); > +static_assert(test_return_type<int, 1, 2>()); > +static_assert(test_return_type<int, 1, 3, 4>()); > diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/rank_type.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/rank_type.cc > new file mode 100644 > index 00000000000..420159fff86 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/rank_type.cc > @@ -0,0 +1,7 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +#include <type_traits> > + > +static_assert(std::is_same_v<typename std::extents<int, 1, 2>::rank_type, > + size_t>); > diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/size_type.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/size_type.cc > new file mode 100644 > index 00000000000..1c054a1c7d2 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/size_type.cc > @@ -0,0 +1,16 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +#include <type_traits> > + > + > +template<typename T, size_t... Extents> > + constexpr bool > + test_size_type() > + { > + return std::is_unsigned_v<typename std::extents<T, > Extents...>::size_type>; > + } > + > +static_assert(test_size_type<int, 1, 2>); > +static_assert(test_size_type<unsigned int, 1, 2>); > + > diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/sizeof.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/sizeof.cc > new file mode 100644 > index 00000000000..27c2d5dd25f > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/sizeof.cc > @@ -0,0 +1,10 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +constexpr auto dyn = std::dynamic_extent; > + > +static_assert(sizeof(std::extents<int, 1, 2>) == 1); > +static_assert(sizeof(std::extents<int>) == 1); > + > +static_assert(sizeof(std::extents<int, 1, dyn>) == sizeof(int)); > +static_assert(sizeof(std::extents<char, 1, dyn>) == sizeof(char)); > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/static_extent.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/static_extent.cc > new file mode 100644 > index 00000000000..18b310887e1 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/static_extent.cc > @@ -0,0 +1,15 @@ > +// { dg-do compile { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +constexpr auto dyn = std::dynamic_extent; > + > +static_assert(std::extents<int, 1, 2>::static_extent(0) == 1); > +static_assert(std::extents<int, 1, 2>::static_extent(1) == 2); > + > +static_assert(std::extents<int, 1, dyn>::static_extent(0) == 1); > +static_assert(std::extents<int, 1, dyn>::static_extent(1) == dyn); > + > +static_assert(std::extents<int, dyn, dyn>::static_extent(0) == dyn); > +static_assert(std::extents<int, dyn, dyn>::static_extent(1) == dyn); > -- > 2.49.0 >