[gcc r16-8156] libstdc++: Properly handle forwarding references in __mdspan::__index_type_cast.

Tomasz Kaminski tkaminsk@gcc.gnu.org
Wed Mar 18 14:20:21 GMT 2026


https://gcc.gnu.org/g:b2d37021acbb29f8baa0a1b0dcad762396c76992

commit r16-8156-gb2d37021acbb29f8baa0a1b0dcad762396c76992
Author: Tomasz Kamiński <tkaminsk@redhat.com>
Date:   Tue Mar 10 15:57:35 2026 +0100

    libstdc++: Properly handle forwarding references in __mdspan::__index_type_cast.
    
    The _OIndexType template parameter will maybe deduced to reference, when
    invoked from constructor and operator[]/at (after r16-7645-g66e60479e97640)
    accepting array or span. We need to use forward for class-type and
    remove_cvref_t for is_integral checks.
    
    This resolves LWG4020: extents::index-cast weirdness.
    
    libstdc++-v3/ChangeLog:
    
            * include/std/mdspan (__mdspan::__index_type_cast): Handle
            forwarding referene and use forward for class types.
            * testsuite/23_containers/mdspan/int_like.h (ConstLValueInt)
            (CustomIndexKind::ConstLValue): Define.
            (CustomIndexType): Handle CustomIndexKind::ConstLValue.
            * testsuite/23_containers/mdspan/at.cc: Test with ConstLValueInt.
            * testsuite/23_containers/mdspan/extents/custom_integer.cc: Likewise.
            * testsuite/23_containers/mdspan/mdspan.cc: Likewise.
    
    Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
    Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>

Diff:
---
 libstdc++-v3/include/std/mdspan                               |  9 ++++++---
 libstdc++-v3/testsuite/23_containers/mdspan/at.cc             |  1 +
 .../testsuite/23_containers/mdspan/extents/custom_integer.cc  |  2 ++
 libstdc++-v3/testsuite/23_containers/mdspan/int_like.h        | 11 +++++++++++
 libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc         |  2 ++
 5 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index f8847642c80e..2d3e82a9980d 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -80,10 +80,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return true;
     }
 
-    template<typename _IndexType, typename _OIndexType>
+    template<typename _IndexType, typename _OIndexTypeRef>
       constexpr _IndexType
-      __index_type_cast(_OIndexType&& __other)
+      __index_type_cast(_OIndexTypeRef&& __other)
       {
+	// _GLIBCXX_RESOLVE_LIB_DEFECTS
+	// 4020. extents::index-cast weirdness
+	using _OIndexType = std::remove_cvref_t<_OIndexTypeRef>;
 	if constexpr (std::is_integral_v<_OIndexType>)
 	  {
 	    constexpr _IndexType __index_type_max
@@ -100,7 +103,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  }
 	else
 	  {
-	    auto __ret = static_cast<_IndexType>(std::move(__other));
+	    auto __ret = static_cast<_IndexType>(std::forward<_OIndexTypeRef>(__other));
 	    if constexpr (std::is_signed_v<_IndexType>)
 	      __glibcxx_assert(__ret >= 0);
 	    return __ret;
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/at.cc b/libstdc++-v3/testsuite/23_containers/mdspan/at.cc
index c5a12d12cccb..367398dd0786 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/at.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/at.cc
@@ -116,4 +116,5 @@ main()
   test_at<ThrowingInt, false, false>();
   test_at<MutatingInt, true, false>();
   test_at<RValueInt, true, false>();
+  test_at<ConstLValueInt, false, true>();
 }
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 99de4015ef31..4e9669c98d8b 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
@@ -86,11 +86,13 @@ main()
   test_shape_all<ThrowingInt, false>();
   test_shape_all<MutatingInt, false>();
   test_shape_all<RValueInt, false>();
+  test_shape_all<ConstLValueInt, true>();
 
   test_pack_all<int, true>();
   test_pack_all<IntLike, true>();
   test_pack_all<ThrowingInt, false>();
   test_pack_all<MutatingInt, true>();
   test_pack_all<RValueInt, true>();
+  test_pack_all<ConstLValueInt, false>();
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h b/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
index b839be73ae94..99ecd155ca4f 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
@@ -7,6 +7,7 @@ enum class CustomIndexKind
   Throwing,
   Mutating,
   RValue,
+  ConstLValue,
 };
 
 template<CustomIndexKind Kind, bool Copyable = false>
@@ -57,6 +58,15 @@ template<CustomIndexKind Kind, bool Copyable = false>
     requires (Kind == CustomIndexKind::RValue)
     { return value; }
 
+    constexpr
+    operator int() const& noexcept
+    requires (Kind == CustomIndexKind::ConstLValue)
+    { return value; }
+
+    operator int() const&&
+    requires (Kind == CustomIndexKind::ConstLValue)	   
+    = delete;
+
   private:
     int value;
   };
@@ -65,6 +75,7 @@ using IntLike = CustomIndexType<CustomIndexKind::Const>;
 using ThrowingInt = CustomIndexType<CustomIndexKind::Throwing>;
 using MutatingInt = CustomIndexType<CustomIndexKind::Mutating>;
 using RValueInt = CustomIndexType<CustomIndexKind::RValue>;
+using ConstLValueInt = CustomIndexType<CustomIndexKind::ConstLValue>;
 
 struct NotIntLike
 { };
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
index a92a05544170..270b3f18daad 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
@@ -755,6 +755,7 @@ main()
   test_from_int_like<ThrowingInt, false, false>();
   test_from_int_like<MutatingInt, true, false>();
   test_from_int_like<RValueInt, true, false>();
+  test_from_int_like<ConstLValueInt, false, true>();
 
   test_from_opaque_accessor();
   test_from_base_class_accessor();
@@ -767,6 +768,7 @@ main()
   test_access<ThrowingInt, false, false>();
   test_access<MutatingInt, true, false>();
   test_access<RValueInt, true, false>();
+  test_access<ConstLValueInt, false, true>();
 
   test_swap();
   static_assert(test_swap());


More information about the Libstdc++-cvs mailing list