[PATCH v1 1/1] libstdc++: Convertibility of rank == 0 layouts, LWG4272.

Luc Grosheintz luc.grosheintz@gmail.com
Tue Jun 10 19:18:50 GMT 2025


LWG4272 proposes to add the condition that convertibility
from layout_stride::mapping to other mappings requires
convertibility of the extents_types.

libstdc++-v3/ChangeLog:

	* include/std/mdspan (layout_left): Apply LWG4272.
	(layout_right): ditto.
	* testsuite/23_containers/mdspan/layouts/ctors.cc: Add
	test to check ctor uniformity at rank == 0. Update test
	for old behavior.

Signed-off-by: Luc Grosheintz <luc.grosheintz@gmail.com>
---
 libstdc++-v3/include/std/mdspan               |  6 +-
 .../23_containers/mdspan/layouts/ctors.cc     | 60 ++++++++++++++++++-
 2 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index 4a3e863bed5..19ed65161fd 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -564,7 +564,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // noexcept for consistency with other layouts.
       template<typename _OExtents>
 	requires is_constructible_v<extents_type, _OExtents>
-	constexpr explicit(extents_type::rank() > 0)
+	constexpr explicit(!(extents_type::rank() == 0
+	                     && is_convertible_v<_OExtents, extents_type>))
 	mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
 	: mapping(__other.extents(), __mdspan::__internal_ctor{})
 	{ __glibcxx_assert(*this == __other); }
@@ -701,7 +702,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       template<class _OExtents>
 	requires is_constructible_v<extents_type, _OExtents>
-	constexpr explicit(extents_type::rank() > 0)
+	constexpr explicit(!(extents_type::rank() == 0
+	                     && is_convertible_v<_OExtents, extents_type>))
 	mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
 	: mapping(__other.extents(), __mdspan::__internal_ctor{})
 	{ __glibcxx_assert(*this == __other); }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
index 23c0a55dae1..4f36715cfab 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
@@ -321,6 +321,61 @@ namespace from_left_or_right
     }
 }
 
+// checks: convertibility of rank == 0 mappings.
+namespace from_rank0
+{
+  template<typename SLayout, typename OLayout, typename SExtents,
+	   typename OExtents>
+    constexpr void
+    verify_ctor()
+    {
+      using SMapping = typename SLayout::mapping<SExtents>;
+      using OMapping = typename OLayout::mapping<OExtents>;
+
+      constexpr bool expected = std::is_convertible_v<OExtents, SExtents>;
+      if constexpr (expected)
+	verify_nothrow_convertible<SMapping>(OMapping{});
+      else
+	verify_nothrow_constructible<SMapping>(OMapping{});
+    }
+
+  template<typename Layout, typename OLayout>
+    constexpr void
+    test_rank0_convertibility()
+    {
+      using E1 = std::extents<int>;
+      using E2 = std::extents<unsigned int>;
+
+      verify_ctor<Layout, OLayout, E1, E2>();
+      verify_ctor<Layout, OLayout, E2, E1>();
+
+      verify_ctor<Layout, OLayout, E2, E2>();
+      verify_ctor<Layout, OLayout, E1, E1>();
+    }
+
+  constexpr void
+  test_all()
+  {
+    auto run = []<typename Layout>(Layout)
+      {
+	test_rank0_convertibility<Layout, std::layout_left>();
+	test_rank0_convertibility<Layout, std::layout_right>();
+	test_rank0_convertibility<Layout, std::layout_stride>();
+      };
+
+    auto run_all = [run]()
+      {
+	run(std::layout_left{});
+	run(std::layout_right{});
+	run(std::layout_stride{});
+	return true;
+      };
+
+    run_all();
+    static_assert(run_all());
+  }
+}
+
 // ctor: mapping(layout_stride::mapping<OExtents>)
 namespace from_stride
 {
@@ -381,8 +436,7 @@ namespace from_stride
       verify_nothrow_convertible<Layout, std::extents<unsigned int>>(
 	std::extents<int>{});
 
-      // Rank ==  0 doesn't check IndexType for convertibility.
-      verify_nothrow_convertible<Layout, std::extents<int>>(
+      verify_nothrow_constructible<Layout, std::extents<int>>(
 	std::extents<unsigned int>{});
 
       verify_nothrow_constructible<Layout, std::extents<int, 3>>(
@@ -432,5 +486,7 @@ main()
 
   from_left_or_right::test_all<std::layout_left, std::layout_right>();
   from_left_or_right::test_all<std::layout_right, std::layout_left>();
+
+  from_rank0::test_all();
   return 0;
 }
-- 
2.49.0



More information about the Libstdc++ mailing list