This shows how useful refactoring for a test was. Thanks for posting.
Just merged to master.

On Wed, Jul 16, 2025 at 10:05 PM Jonathan Wakely <jwakely....@gmail.com>
wrote:

>
>
> On Wed, 16 Jul 2025, 14:46 Luc Grosheintz, <luc.groshei...@gmail.com>
> wrote:
>
>> PR121061 consists of two bugs for mdspan related code. This commit fixes
>> the first one. Namely, when passing custom IndexType as an array or
>> span, the conversion to int must be const. Prior to this commit the
>> constraint incorrectly also allowed non-const conversion. This commit
>> updates all related constraints to check
>>
>>   __valid_index_type<const OtherIndexType&, index_type>
>>
>> in those cases. Also adds a MutatingInt to int_like.h which only
>> supports non-const conversion to int and updates the tests.
>>
>
> OK for trunk
>
>
>>         PR libstdc++/121061
>>
>> libstdc++-v3/ChangeLog:
>>
>>         * include/std/mdspan (extents::extents): Fix constraint to
>>         prevent non-const conversion to index_type.
>>         (layout_stride::mapping::mapping): Ditto.
>>         (mdspan::mdspan): Ditto.
>>         (mdspan::operator[]): Ditto.
>>         * testsuite/23_containers/mdspan/extents/custom_integer.cc: Add
>>         test for MutatingInt.
>>         * testsuite/23_containers/mdspan/int_like.h (MutatingInt): Add.
>>         * testsuite/23_containers/mdspan/layouts/mapping.cc: Add test for
>>         MutatingInt.
>>         * testsuite/23_containers/mdspan/layouts/stride.cc: Ditto.
>>         * testsuite/23_containers/mdspan/mdspan.cc: Ditto.
>>
>> Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com>
>> ---
>>  libstdc++-v3/include/std/mdspan               | 34 +++++++++++--------
>>  .../mdspan/extents/custom_integer.cc          |  1 +
>>  .../testsuite/23_containers/mdspan/int_like.h |  7 ++++
>>  .../23_containers/mdspan/layouts/mapping.cc   |  3 ++
>>  .../23_containers/mdspan/layouts/stride.cc    |  1 +
>>  .../testsuite/23_containers/mdspan/mdspan.cc  |  2 ++
>>  6 files changed, 34 insertions(+), 14 deletions(-)
>>
>> diff --git a/libstdc++-v3/include/std/mdspan
>> b/libstdc++-v3/include/std/mdspan
>> index b34116a85e6..930997e9536 100644
>> --- a/libstdc++-v3/include/std/mdspan
>> +++ b/libstdc++-v3/include/std/mdspan
>> @@ -288,15 +288,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>             initializer_list{_S_storage::_S_int_cast(__exts)...}))
>>         { }
>>
>> -      template<__mdspan::__valid_index_type<index_type> _OIndexType,
>> size_t _Nm>
>> -       requires (_Nm == rank() || _Nm == rank_dynamic())
>> +      template<typename _OIndexType, size_t _Nm>
>> +       requires __mdspan::__valid_index_type<const _OIndexType&,
>> index_type>
>> +         && (_Nm == rank() || _Nm == rank_dynamic())
>>         constexpr explicit(_Nm != rank_dynamic())
>>         extents(span<_OIndexType, _Nm> __exts) noexcept
>>         : _M_exts(span<const _OIndexType, _Nm>(__exts))
>>         { }
>>
>> -      template<__mdspan::__valid_index_type<index_type> _OIndexType,
>> size_t _Nm>
>> -       requires (_Nm == rank() || _Nm == rank_dynamic())
>> +      template<typename _OIndexType, size_t _Nm>
>> +       requires __mdspan::__valid_index_type<const _OIndexType&,
>> index_type>
>> +         && (_Nm == rank() || _Nm == rank_dynamic())
>>         constexpr explicit(_Nm != rank_dynamic())
>>         extents(const array<_OIndexType, _Nm>& __exts) noexcept
>>         : _M_exts(span<const _OIndexType, _Nm>(__exts))
>> @@ -878,7 +880,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        constexpr
>>        mapping(const mapping&) noexcept = default;
>>
>> -      template<__mdspan::__valid_index_type<index_type> _OIndexType>
>> +      template<typename _OIndexType>
>> +       requires __mdspan::__valid_index_type<const _OIndexType&,
>> index_type>
>>         constexpr
>>         mapping(const extents_type& __exts,
>>                 span<_OIndexType, extents_type::rank()> __strides)
>> noexcept
>> @@ -888,7 +891,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>             _M_strides[__i] = index_type(as_const(__strides[__i]));
>>         }
>>
>> -      template<__mdspan::__valid_index_type<index_type> _OIndexType>
>> +      template<typename _OIndexType>
>> +       requires __mdspan::__valid_index_type<const _OIndexType&,
>> index_type>
>>         constexpr
>>         mapping(const extents_type& __exts,
>>                 const array<_OIndexType, extents_type::rank()>& __strides)
>> @@ -1134,9 +1138,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>           _M_handle(std::move(__handle))
>>         { }
>>
>> -      template<__mdspan::__valid_index_type<index_type> _OIndexType,
>> -              size_t _Nm>
>> -       requires (_Nm == rank() || _Nm == rank_dynamic())
>> +      template<typename _OIndexType, size_t _Nm>
>> +       requires __mdspan::__valid_index_type<const _OIndexType&,
>> index_type>
>> +                && (_Nm == rank() || _Nm == rank_dynamic())
>>                  && is_constructible_v<mapping_type, extents_type>
>>                  && is_default_constructible_v<accessor_type>
>>         constexpr explicit(_Nm != rank_dynamic())
>> @@ -1145,9 +1149,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>           _M_handle(std::move(__handle))
>>         { }
>>
>> -      template<__mdspan::__valid_index_type<index_type> _OIndexType,
>> -              size_t _Nm>
>> -       requires (_Nm == rank() || _Nm == rank_dynamic())
>> +      template<typename _OIndexType, size_t _Nm>
>> +       requires __mdspan::__valid_index_type<const _OIndexType&,
>> index_type>
>> +                && (_Nm == rank() || _Nm == rank_dynamic())
>>                  && is_constructible_v<mapping_type, extents_type>
>>                  && is_default_constructible_v<accessor_type>
>>         constexpr explicit(_Nm != rank_dynamic())
>> @@ -1218,7 +1222,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>           return _M_accessor.access(_M_handle, __index);
>>         }
>>
>> -      template<__mdspan::__valid_index_type<index_type> _OIndexType>
>> +      template<typename _OIndexType>
>> +       requires __mdspan::__valid_index_type<const _OIndexType&,
>> index_type>
>>         constexpr reference
>>         operator[](span<_OIndexType, rank()> __indices) const
>>         {
>> @@ -1228,7 +1233,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>           return __call(make_index_sequence<rank()>());
>>         }
>>
>> -      template<__mdspan::__valid_index_type<index_type> _OIndexType>
>> +      template<typename _OIndexType>
>> +       requires __mdspan::__valid_index_type<const _OIndexType&,
>> index_type>
>>         constexpr reference
>>         operator[](const array<_OIndexType, rank()>& __indices) const
>>         { return (*this)[span<const _OIndexType, rank()>(__indices)]; }
>> diff --git
>> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
>> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
>> index 4f631815b10..92c2ebb46e1 100644
>> ---
>> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
>> +++
>> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
>> @@ -84,6 +84,7 @@ main()
>>    test_shape_all<int, true>();
>>    test_shape_all<IntLike, true>();
>>    test_shape_all<ThrowingInt, false>();
>> +  test_shape_all<MutatingInt, false>();
>>
>>    test_pack_all<int, true>();
>>    test_pack_all<IntLike, true>();
>> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
>> b/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
>> index ed45375f986..f4f4a773193 100644
>> --- a/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
>> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
>> @@ -5,6 +5,7 @@ enum class CustomIndexKind
>>  {
>>    Const,
>>    Throwing,
>> +  Mutating,
>>  };
>>
>>  template<CustomIndexKind Kind>
>> @@ -36,12 +37,18 @@ template<CustomIndexKind Kind>
>>      requires (Kind == CustomIndexKind::Throwing)
>>      { return _M_i; }
>>
>> +    constexpr
>> +    operator int() noexcept
>> +    requires (Kind == CustomIndexKind::Mutating)
>> +    { return _M_i; }
>> +
>>    private:
>>      int _M_i;
>>    };
>>
>>  using IntLike = CustomIndexType<CustomIndexKind::Const>;
>>  using ThrowingInt = CustomIndexType<CustomIndexKind::Throwing>;
>> +using MutatingInt = CustomIndexType<CustomIndexKind::Mutating>;
>>
>>  struct NotIntLike
>>  { };
>> diff --git
>> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
>> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
>> index 17f0c00acf2..6742fa11a51 100644
>> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
>> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
>> @@ -180,6 +180,7 @@ template<typename Layout>
>>      static_assert(has_linear_index<Mapping, int>);
>>      static_assert(has_linear_index<Mapping, double>);
>>      static_assert(has_linear_index<Mapping, IntLike>);
>> +    static_assert(has_linear_index<Mapping, MutatingInt>);
>>      static_assert(!has_linear_index<Mapping, ThrowingInt>);
>>      static_assert(!has_linear_index<Mapping, NotIntLike>);
>>      static_assert(!has_linear_index<Mapping, int, int>);
>> @@ -194,6 +195,7 @@ template<typename Layout>
>>      static_assert(has_linear_index<Mapping, int, int>);
>>      static_assert(has_linear_index<Mapping, double, double>);
>>      static_assert(has_linear_index<Mapping, IntLike, int>);
>> +    static_assert(has_linear_index<Mapping, MutatingInt, int>);
>>      static_assert(!has_linear_index<Mapping, ThrowingInt, int>);
>>      static_assert(!has_linear_index<Mapping, NotIntLike, int>);
>>      static_assert(!has_linear_index<Mapping, int, int, int>);
>> @@ -524,6 +526,7 @@ template<typename Layout>
>>      if !consteval
>>        {
>>         test_linear_index_all<Layout, IntLike>();
>> +       test_linear_index_all<Layout, MutatingInt>();
>>        }
>>
>>      test_required_span_size_all<Layout>();
>> diff --git
>> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc
>> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc
>> index 1267306fb5c..8d2fad2936f 100644
>> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc
>> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc
>> @@ -65,6 +65,7 @@ test_stride_constructible_all()
>>    test_stride_constructible<E0, E0, int, 0, true>();
>>    test_stride_constructible<E0, E0, IntLike, 0, true>();
>>    test_stride_constructible<E0, E0, ThrowingInt, 0, false>();
>> +  test_stride_constructible<E0, E0, MutatingInt, 0, false>();
>>    test_stride_constructible<E0, E0, NotIntLike, 0, false>();
>>    test_stride_constructible<E1, E1, int, 1, true>();
>>    test_stride_constructible<E2, E1, int, 1, true>();
>> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
>> b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
>> index adabb0c6639..22ec68ea2d1 100644
>> --- a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
>> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
>> @@ -693,6 +693,7 @@ main()
>>    static_assert(test_from_int_like<int, true, true>());
>>    test_from_int_like<IntLike, true, true>();
>>    test_from_int_like<ThrowingInt, false, false>();
>> +  test_from_int_like<MutatingInt, true, false>();
>>
>>    test_from_opaque_accessor();
>>    test_from_base_class_accessor();
>> @@ -703,6 +704,7 @@ main()
>>    static_assert(test_access<int, true, true>());
>>    test_access<IntLike, true, true>();
>>    test_access<ThrowingInt, false, false>();
>> +  test_access<MutatingInt, true, false>();
>>
>>    test_swap();
>>    static_assert(test_swap());
>> --
>> 2.50.0
>>
>>

Reply via email to