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 > >