https://gcc.gnu.org/g:1eee8430794f790b6d364603685e70d83d8d42f5

commit r16-2327-g1eee8430794f790b6d364603685e70d83d8d42f5
Author: Luc Grosheintz <luc.groshei...@gmail.com>
Date:   Wed Jul 16 15:45:44 2025 +0200

    libstdc++: Fix constraint for custom integer types in mdspan [PR121061]
    
    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.
    
    Reviewed-by: Jonathan Wakely <jwak...@redhat.com>
    Reviewed-by: Tomasz KamiƄski <tkami...@redhat.com>
    Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com>

Diff:
---
 libstdc++-v3/include/std/mdspan                    | 34 +++++++++++++---------
 .../23_containers/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 b34116a85e67..930997e95360 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 4f631815b101..92c2ebb46e1b 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 ed45375f9866..f4f4a7731931 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 17f0c00acf29..6742fa11a514 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 1267306fb5c2..8d2fad2936f6 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 adabb0c66397..22ec68ea2d1d 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());

Reply via email to