[libcxx-commits] [libcxx] [libc++] LWG4272: For `rank == 0`, `layout_stride` is atypically convertible (PR #191507)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Apr 10 13:00:33 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: eiytoq (eiytoq)
<details>
<summary>Changes</summary>
This PR implements the LWG fix for non-padded layouts (`layout_left` / `layout_right`).
Partially fixes #<!-- -->171327. The padded-layout part is handled in #<!-- -->187873.
---
Full diff: https://github.com/llvm/llvm-project/pull/191507.diff
5 Files Affected:
- (modified) libcxx/include/__mdspan/layout_left.h (+2-1)
- (modified) libcxx/include/__mdspan/layout_right.h (+2-1)
- (modified) libcxx/include/mdspan (+2-2)
- (modified) libcxx/test/std/containers/views/mdspan/layout_left/ctor.layout_stride.pass.cpp (+3-2)
- (modified) libcxx/test/std/containers/views/mdspan/layout_right/ctor.layout_stride.pass.cpp (+3-2)
``````````diff
diff --git a/libcxx/include/__mdspan/layout_left.h b/libcxx/include/__mdspan/layout_left.h
index 2f515afb6c860..e56a0e589ffb6 100644
--- a/libcxx/include/__mdspan/layout_left.h
+++ b/libcxx/include/__mdspan/layout_left.h
@@ -111,7 +111,8 @@ class layout_left::mapping {
template <class _OtherExtents>
requires(is_constructible_v<extents_type, _OtherExtents>)
- _LIBCPP_HIDE_FROM_ABI constexpr explicit(extents_type::rank() > 0)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(
+ !(extents_type::rank() == 0 && is_convertible_v<_OtherExtents, extents_type>))
mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept
: __extents_(__other.extents()) {
if constexpr (extents_type::rank() > 0) {
diff --git a/libcxx/include/__mdspan/layout_right.h b/libcxx/include/__mdspan/layout_right.h
index ccfbd23e28ad7..231513866f684 100644
--- a/libcxx/include/__mdspan/layout_right.h
+++ b/libcxx/include/__mdspan/layout_right.h
@@ -111,7 +111,8 @@ class layout_right::mapping {
template <class _OtherExtents>
requires(is_constructible_v<extents_type, _OtherExtents>)
- _LIBCPP_HIDE_FROM_ABI constexpr explicit(extents_type::rank() > 0)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(
+ !(extents_type::rank() == 0 && is_convertible_v<_OtherExtents, extents_type>))
mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept
: __extents_(__other.extents()) {
if constexpr (extents_type::rank() > 0) {
diff --git a/libcxx/include/mdspan b/libcxx/include/mdspan
index 32468a128dc9a..95c0c330b821e 100644
--- a/libcxx/include/mdspan
+++ b/libcxx/include/mdspan
@@ -113,7 +113,7 @@ namespace std {
constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
mapping(const layout_right::mapping<OtherExtents>&) noexcept;
template<class OtherExtents>
- constexpr explicit(extents_type::rank() > 0)
+ constexpr explicit(see below)
mapping(const layout_stride::mapping<OtherExtents>&) noexcept;
constexpr mapping& operator=(const mapping&) noexcept = default;
@@ -167,7 +167,7 @@ namespace std {
constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
mapping(const layout_left::mapping<OtherExtents>&) noexcept;
template<class OtherExtents>
- constexpr explicit(extents_type::rank() > 0)
+ constexpr explicit(see below)
mapping(const layout_stride::mapping<OtherExtents>&) noexcept;
constexpr mapping& operator=(const mapping&) noexcept = default;
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left/ctor.layout_stride.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left/ctor.layout_stride.pass.cpp
index cbd759eaf72cb..3bd5127177893 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_left/ctor.layout_stride.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_left/ctor.layout_stride.pass.cpp
@@ -11,7 +11,7 @@
// <mdspan>
// template<class OtherExtents>
-// constexpr explicit(extents_type::rank() > 0)
+// constexpr explicit(see below)
// mapping(const layout_stride::mapping<OtherExtents>& other);
//
// Constraints: is_constructible_v<extents_type, OtherExtents> is true.
@@ -58,9 +58,10 @@ constexpr void test_conversion(FromE src_exts) {
template <class T1, class T2>
constexpr void test_conversion() {
constexpr size_t D = std::dynamic_extent;
+ constexpr bool ext_convertible = std::is_convertible_v<std::extents<T2>, std::extents<T1>>;
// clang-format off
- test_conversion<true, std::extents<T1>>(std::extents<T2>());
+ test_conversion<ext_convertible, std::extents<T1>>(std::extents<T2>());
test_conversion<false, std::extents<T1, D>>(std::extents<T2, D>(5));
test_conversion<false, std::extents<T1, 5>>(std::extents<T2, D>(5));
test_conversion<false, std::extents<T1, 5>>(std::extents<T2, 5>());
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right/ctor.layout_stride.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right/ctor.layout_stride.pass.cpp
index 5886eba9d15ee..d7b76277b6310 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_right/ctor.layout_stride.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_right/ctor.layout_stride.pass.cpp
@@ -11,7 +11,7 @@
// <mdspan>
// template<class OtherExtents>
-// constexpr explicit(extents_type::rank() > 0)
+// constexpr explicit(see below)
// mapping(const layout_stride::mapping<OtherExtents>& other);
//
// Constraints: is_constructible_v<extents_type, OtherExtents> is true.
@@ -58,9 +58,10 @@ constexpr void test_conversion(FromE src_exts) {
template <class T1, class T2>
constexpr void test_conversion() {
constexpr size_t D = std::dynamic_extent;
+ constexpr bool ext_convertible = std::is_convertible_v<std::extents<T2>, std::extents<T1>>;
// clang-format off
- test_conversion<true, std::extents<T1>>(std::extents<T2>());
+ test_conversion<ext_convertible, std::extents<T1>>(std::extents<T2>());
test_conversion<false, std::extents<T1, D>>(std::extents<T2, D>(5));
test_conversion<false, std::extents<T1, 5>>(std::extents<T2, D>(5));
test_conversion<false, std::extents<T1, 5>>(std::extents<T2, 5>());
``````````
</details>
https://github.com/llvm/llvm-project/pull/191507
More information about the libcxx-commits
mailing list