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
>

Reply via email to