[PATCH v1 2/3] libstdc++: Fix constraint for custom integer types in mdspan [PR121061]

Luc Grosheintz luc.grosheintz@gmail.com
Wed Jul 16 13:45:44 GMT 2025


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.

	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.grosheintz@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



More information about the Libstdc++ mailing list