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