From e0dd9c0a604d5ee9aa365cef3522e8b69b365ed3 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Tue, 9 Sep 2025 17:04:05 +0200 Subject: [PATCH] libstdc++: Convertibility of rank == 0 layouts, LWG4272. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit LWG4272 proposes to add a condition for convertibility from layout_stride::mapping to other mappings. New conversion requires both that rank == 0 and that the extent types are convertible. LWG4272 also proposes to add the same condition for conversion of padded layouts, i.e. in addition to the condition on the padding value, the extent types must be convertible. libstdc++-v3/ChangeLog: * include/std/mdspan (layout_left): Apply LWG4272. (layout_right, layout_left_padded, layout_right_padded): Ditto. * testsuite/23_containers/mdspan/layouts/ctors.cc: Add test to check ctor uniformity at rank == 0. Update test for new behavior. * testsuite/23_containers/mdspan/layouts/padded.cc: Update test for new behavior. Co-authored-by: Tomasz Kamiński Signed-off-by: Luc Grosheintz Signed-off-by: Tomasz Kamiński --- libstdc++-v3/include/std/mdspan | 36 +++++--- .../23_containers/mdspan/layouts/ctors.cc | 82 +++++++++++++++---- .../23_containers/mdspan/layouts/padded.cc | 13 ++- 3 files changed, 96 insertions(+), 35 deletions(-) diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan index bfec288aded..03cc4f02a1c 100644 --- a/libstdc++-v3/include/std/mdspan +++ b/libstdc++-v3/include/std/mdspan @@ -935,7 +935,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // noexcept for consistency with other layouts. template requires is_constructible_v - 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); } @@ -1102,7 +1103,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template requires is_constructible_v - 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); } @@ -1920,18 +1922,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template requires is_constructible_v<_OExtents, extents_type> - constexpr explicit(_OExtents::rank() > 0) + constexpr explicit(!(_OExtents::rank() == 0 + && is_convertible_v<_OExtents, extents_type>)) mapping(const typename layout_stride::mapping<_OExtents>& __other) : _M_storage(__other) { __glibcxx_assert(*this == __other); } - template - requires __mdspan::__is_left_padded_mapping<_LeftpadMapping> + template + requires __mdspan::__is_left_padded_mapping<_LeftPaddedMapping> && is_constructible_v - constexpr explicit(_S_rank > 1 && (padding_value != dynamic_extent - || _LeftpadMapping::padding_value == dynamic_extent)) - mapping(const _LeftpadMapping& __other) + typename _LeftPaddedMapping::extents_type> + constexpr explicit( + !is_convertible_v + || _S_rank > 1 && (padding_value != dynamic_extent + || _LeftPaddedMapping::padding_value == dynamic_extent)) + mapping(const _LeftPaddedMapping& __other) : _M_storage(layout_left{}, __other) { } @@ -2081,7 +2087,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template requires is_constructible_v<_OExtents, extents_type> - constexpr explicit(_OExtents::rank() > 0) + constexpr explicit(!(_OExtents::rank() == 0 + && is_convertible_v<_OExtents, extents_type>)) mapping(const typename layout_stride::mapping<_OExtents>& __other) : _M_storage(__other) { __glibcxx_assert(*this == __other); } @@ -2090,8 +2097,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping> && is_constructible_v - constexpr explicit(_S_rank > 1 && (padding_value != dynamic_extent - || _RightPaddedMapping::padding_value == dynamic_extent)) + constexpr explicit( + !is_convertible_v + || _S_rank > 1 && (padding_value != dynamic_extent + || _RightPaddedMapping::padding_value == dynamic_extent)) mapping(const _RightPaddedMapping& __other) : _M_storage(layout_right{}, __other) { } @@ -2638,7 +2648,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } else __glibcxx_assert(__idx <= __ext.extent(0)); - } +} template constexpr void diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc index 80ae5d8d56a..b6e4138196d 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc @@ -239,12 +239,8 @@ namespace from_same_layout verify_nothrow_convertible>( std::extents{}); - if constexpr (!is_padded_layout) - verify_nothrow_constructible>( - std::extents{}); - else - verify_convertible>( - std::extents{}); + verify_nothrow_constructible>( + std::extents{}); assert_not_constructible< typename Layout::mapping>, @@ -254,12 +250,8 @@ namespace from_same_layout typename Layout::mapping>, typename Layout::mapping>>(); - if constexpr (!is_padded_layout) - verify_nothrow_constructible>( - std::extents{1}); - else - verify_convertible>( - std::extents{1}); + verify_nothrow_constructible>( + std::extents{1}); verify_nothrow_convertible>( std::extents{}); @@ -349,6 +341,67 @@ namespace from_left_or_right } } +// checks: convertibility of rank == 0 mappings. +namespace from_rank0 +{ + template + constexpr void + verify_ctor() + { + using SMapping = typename SLayout::mapping; + using OMapping = typename OLayout::mapping; + + constexpr bool expected = std::is_convertible_v; + if constexpr (expected) + verify_nothrow_convertible(OMapping{}); + else + verify_nothrow_constructible(OMapping{}); + } + + template + constexpr void + test_rank0_convertibility() + { + using E1 = std::extents; + using E2 = std::extents; + + verify_ctor(); + verify_ctor(); + + verify_ctor(); + verify_ctor(); + } + + constexpr void + test_all() + { + auto run = [](Layout) + { + test_rank0_convertibility(); + test_rank0_convertibility(); + test_rank0_convertibility(); + }; + + auto run_all = [run]() + { + run(std::layout_left{}); + run(std::layout_right{}); + run(std::layout_stride{}); +#if __cplusplus > 202302L + run(std::layout_left_padded<0>{}); + run(std::layout_left_padded<1>{}); + run(std::layout_left_padded<6>{}); + run(std::layout_left_padded{}); +#endif + return true; + }; + + run_all(); + static_assert(run_all()); + } +} + // ctor: mapping(layout_stride::mapping) namespace from_stride { @@ -409,8 +462,7 @@ namespace from_stride verify_nothrow_convertible>( std::extents{}); - // Rank == 0 doesn't check IndexType for convertibility. - verify_nothrow_convertible>( + verify_nothrow_constructible>( std::extents{}); verify_nothrow_constructible>( @@ -474,5 +526,7 @@ main() from_left_or_right::test_all(); from_left_or_right::test_all(); + + from_rank0::test_all(); return 0; } diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc index 19fdf93ce0d..1b6e063d12d 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc @@ -149,7 +149,6 @@ is_same_mapping(const auto& lhs, const auto& rhs) enum class ConversionRule { Never, - Always, Regular }; @@ -159,8 +158,6 @@ should_convert(auto rule) { if constexpr (rule == ConversionRule::Never) return false; - if constexpr (rule == ConversionRule::Always) - return true; else return std::is_convertible_v; @@ -184,7 +181,7 @@ template // There's a twist when both mappings are left-padded. There's two distinct // ctors: a defaulted copy ctor and a constrained template that enables - // construction from left-padded mappings even if their layout_type is + // construction from left-padded mappings even if their layout_type (padding) is // different. The two ctors have different rules regarding conversion. if constexpr (!std::same_as) @@ -329,7 +326,7 @@ template typename Layout> auto check = [](To, auto m) { - constexpr auto cr = std::cw; + constexpr auto cr = std::cw; check_convertible_variants(m, cr); }; @@ -350,7 +347,7 @@ template typename Layout> auto check = [](To, auto m) { - constexpr auto cr = std::cw; + constexpr auto cr = std::cw; check_convertible_variants(m, cr); }; @@ -373,7 +370,7 @@ template typename Layout> typename Layout<6>::mapping msta{E1{}}; typename Layout::mapping mdyn{E1{}}; - constexpr auto calways = std::cw; + constexpr auto cregular = std::cw; constexpr auto cnever = std::cw; auto check = [](To, auto m, auto cr) @@ -381,7 +378,7 @@ template typename Layout> check(Layout<6>{}, msta, cnever); check(Layout<6>{}, mdyn, cnever); - check(Layout{}, msta, calways); + check(Layout{}, msta, cregular); check(Layout{}, mdyn, cnever); } -- 2.47.3