[PATCH v1] libstdc++: Fix class mandate for extents.

Luc Grosheintz luc.grosheintz@gmail.com
Wed May 14 19:25:00 GMT 2025


To make review easier, I'd like to provide links to the
sections in the standard I used.

mandate: https://eel.is/c++draft/mdspan.extents#overview-1.1

signed integer: https://eel.is/c++draft/basic.fundamental#1
unsigned integer: https://eel.is/c++draft/basic.fundamental#2

integral: https://eel.is/c++draft/basic.fundamental#11
           https://eel.is/c++draft/meta#tab:meta.unary.cat-row-4

On 5/14/25 9:13 PM, Luc Grosheintz wrote:
> The standard states that the IndexType must be a signed or unsigned
> integer. This mandate was implemented using `std::is_integral_v`. Which
> also includes (among others) char and bool, which neither signed nor
> unsigned integers.
> 
> libstdc++-v3/ChangeLog:
> 
> 	* include/std/mdspan: Implement the mandate for extents as
> 	signed or unsigned integer and not any interal type.
> 	* testsuite/23_containers/mdspan/extents/class_mandates_neg.cc: Check
> 	that extents<char,...> and extents<bool,...> are invalid.
> 	* testsuite/23_containers/mdspan/extents/misc.cc: Update
> 	tests to avoid `char` and `bool` as IndexType.
> ---
>   libstdc++-v3/include/std/mdspan                        |  3 ++-
>   .../23_containers/mdspan/extents/class_mandates_neg.cc | 10 +++++++---
>   .../testsuite/23_containers/mdspan/extents/misc.cc     |  8 ++++----
>   3 files changed, 13 insertions(+), 8 deletions(-)
> 
> diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
> index aee96dda7cd..22509d9c8f4 100644
> --- a/libstdc++-v3/include/std/mdspan
> +++ b/libstdc++-v3/include/std/mdspan
> @@ -163,7 +163,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>     template<typename _IndexType, size_t... _Extents>
>       class extents
>       {
> -      static_assert(is_integral_v<_IndexType>, "_IndexType must be integral.");
> +      static_assert(__is_standard_integer<_IndexType>::value,
> +		    "_IndexType must be a signed or unsigned integer.");
>         static_assert(
>   	  (__mdspan::__valid_static_extent<_Extents, _IndexType> && ...),
>   	  "Extents must either be dynamic or representable as _IndexType");
> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc
> index b654e3920a8..63a2db77c08 100644
> --- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc
> @@ -1,8 +1,12 @@
>   // { dg-do compile { target c++23 } }
>   #include<mdspan>
>   
> -std::extents<char, size_t(1) << 9> e1; // { dg-error "from here" }
> -std::extents<double, 1> e2;            // { dg-error "from here" }
> +#include <cstdint>
> +
> +std::extents<uint8_t, size_t(1) << 9> e1; // { dg-error "from here" }
> +std::extents<char, 1> e2;                 // { dg-error "from here" }
> +std::extents<bool, 1> e3;                 // { dg-error "from here" }
> +std::extents<double, 1> e4;               // { dg-error "from here" }
>   // { dg-prune-output "dynamic or representable as _IndexType" }
> -// { dg-prune-output "must be integral" }
> +// { dg-prune-output "signed or unsigned integer" }
>   // { dg-prune-output "invalid use of incomplete type" }
> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
> index 16204aaaa75..e71fdc54230 100644
> --- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
> @@ -1,6 +1,7 @@
>   // { dg-do run { target c++23 } }
>   #include <mdspan>
>   
> +#include <cstdint>
>   #include <testsuite_hooks.h>
>   
>   constexpr size_t dyn = std::dynamic_extent;
> @@ -20,7 +21,6 @@ static_assert(std::is_same_v<std::extents<int, 1, 2>::rank_type, size_t>);
>   static_assert(std::is_unsigned_v<std::extents<int, 2>::size_type>);
>   static_assert(std::is_unsigned_v<std::extents<unsigned int, 2>::size_type>);
>   
> -static_assert(std::is_same_v<std::extents<char, 2>::index_type, char>);
>   static_assert(std::is_same_v<std::extents<int, 2>::index_type, int>);
>   static_assert(std::is_same_v<std::extents<unsigned int, 2>::index_type,
>   	      unsigned int>);
> @@ -49,7 +49,7 @@ static_assert(check_rank_return_types<int, 1>());
>   
>   // Check that the static extents don't take up space.
>   static_assert(sizeof(std::extents<int, 1, dyn>) == sizeof(int));
> -static_assert(sizeof(std::extents<char, 1, dyn>) == sizeof(char));
> +static_assert(sizeof(std::extents<short, 1, dyn>) == sizeof(short));
>   
>   template<typename Extents>
>   class Container
> @@ -58,7 +58,7 @@ class Container
>     [[no_unique_address]] std::extents<size_t> b0;
>   };
>   
> -static_assert(sizeof(Container<std::extents<char, 1, 2>>) == sizeof(int));
> +static_assert(sizeof(Container<std::extents<short, 1, 2>>) == sizeof(int));
>   static_assert(sizeof(Container<std::extents<size_t, 1, 2>>) == sizeof(int));
>   
>   // operator=
> @@ -103,7 +103,7 @@ test_deduction_all()
>     test_deduction<0>();
>     test_deduction<1>(1);
>     test_deduction<2>(1.0, 2.0f);
> -  test_deduction<3>(int(1), char(2), size_t(3));
> +  test_deduction<3>(int(1), short(2), size_t(3));
>     return true;
>   }
>   



More information about the Libstdc++ mailing list