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