mirror of git://gcc.gnu.org/git/gcc.git
libstdc++: Convertibility of rank == 0 layouts, LWG4272.
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 <tkaminsk@redhat.com> Signed-off-by: Luc Grosheintz <luc.grosheintz@gmail.com> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
This commit is contained in:
parent
409114931c
commit
e0dd9c0a60
|
|
@ -935,7 +935,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); }
|
||||
|
|
@ -1102,7 +1103,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
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); }
|
||||
|
|
@ -1920,18 +1922,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
template<typename _OExtents>
|
||||
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<typename _LeftpadMapping>
|
||||
requires __mdspan::__is_left_padded_mapping<_LeftpadMapping>
|
||||
template<typename _LeftPaddedMapping>
|
||||
requires __mdspan::__is_left_padded_mapping<_LeftPaddedMapping>
|
||||
&& is_constructible_v<extents_type,
|
||||
typename _LeftpadMapping::extents_type>
|
||||
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<typename _LeftPaddedMapping::extents_type,
|
||||
extents_type>
|
||||
|| _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<typename _OExtents>
|
||||
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<extents_type,
|
||||
typename _RightPaddedMapping::extents_type>
|
||||
constexpr explicit(_S_rank > 1 && (padding_value != dynamic_extent
|
||||
|| _RightPaddedMapping::padding_value == dynamic_extent))
|
||||
constexpr explicit(
|
||||
!is_convertible_v<typename _RightPaddedMapping::extents_type,
|
||||
extents_type>
|
||||
|| _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<typename _IndexType, size_t _Extent, typename _Slice>
|
||||
constexpr void
|
||||
|
|
|
|||
|
|
@ -239,12 +239,8 @@ namespace from_same_layout
|
|||
verify_nothrow_convertible<Layout, std::extents<unsigned int>>(
|
||||
std::extents<int>{});
|
||||
|
||||
if constexpr (!is_padded_layout<Layout>)
|
||||
verify_nothrow_constructible<Layout, std::extents<int>>(
|
||||
std::extents<unsigned int>{});
|
||||
else
|
||||
verify_convertible<Layout, std::extents<int>>(
|
||||
std::extents<unsigned int>{});
|
||||
verify_nothrow_constructible<Layout, std::extents<int>>(
|
||||
std::extents<unsigned int>{});
|
||||
|
||||
assert_not_constructible<
|
||||
typename Layout::mapping<std::extents<int>>,
|
||||
|
|
@ -254,12 +250,8 @@ namespace from_same_layout
|
|||
typename Layout::mapping<std::extents<int, 1>>,
|
||||
typename Layout::mapping<std::extents<int>>>();
|
||||
|
||||
if constexpr (!is_padded_layout<Layout>)
|
||||
verify_nothrow_constructible<Layout, std::extents<int, 1>>(
|
||||
std::extents<int, dyn>{1});
|
||||
else
|
||||
verify_convertible<Layout, std::extents<int, 1>>(
|
||||
std::extents<int, dyn>{1});
|
||||
verify_nothrow_constructible<Layout, std::extents<int, 1>>(
|
||||
std::extents<int, dyn>{1});
|
||||
|
||||
verify_nothrow_convertible<Layout, std::extents<int, dyn>>(
|
||||
std::extents<int, 1>{});
|
||||
|
|
@ -349,6 +341,67 @@ 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{});
|
||||
#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<dyn>{});
|
||||
#endif
|
||||
return true;
|
||||
};
|
||||
|
||||
run_all();
|
||||
static_assert(run_all());
|
||||
}
|
||||
}
|
||||
|
||||
// ctor: mapping(layout_stride::mapping<OExtents>)
|
||||
namespace from_stride
|
||||
{
|
||||
|
|
@ -409,8 +462,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>>(
|
||||
|
|
@ -474,5 +526,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<typename From::extents_type,
|
||||
typename To::extents_type>;
|
||||
|
|
@ -184,7 +181,7 @@ template<typename LayoutTo, typename Esta, typename Edyn, typename Ewrong>
|
|||
|
||||
// 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<LayoutTo, LayoutFrom>)
|
||||
|
|
@ -329,7 +326,7 @@ template<template<size_t> typename Layout>
|
|||
|
||||
auto check = []<typename To>(To, auto m)
|
||||
{
|
||||
constexpr auto cr = std::cw<ConversionRule::Always>;
|
||||
constexpr auto cr = std::cw<ConversionRule::Regular>;
|
||||
check_convertible_variants<To, E1, E2, E3>(m, cr);
|
||||
};
|
||||
|
||||
|
|
@ -350,7 +347,7 @@ template<template<size_t> typename Layout>
|
|||
|
||||
auto check = []<typename To>(To, auto m)
|
||||
{
|
||||
constexpr auto cr = std::cw<ConversionRule::Always>;
|
||||
constexpr auto cr = std::cw<ConversionRule::Regular>;
|
||||
check_convertible_variants<To, E1, E2, E3>(m, cr);
|
||||
};
|
||||
|
||||
|
|
@ -373,7 +370,7 @@ template<template<size_t> typename Layout>
|
|||
typename Layout<6>::mapping<E1> msta{E1{}};
|
||||
typename Layout<dyn>::mapping<E1> mdyn{E1{}};
|
||||
|
||||
constexpr auto calways = std::cw<ConversionRule::Always>;
|
||||
constexpr auto cregular = std::cw<ConversionRule::Regular>;
|
||||
constexpr auto cnever = std::cw<ConversionRule::Never>;
|
||||
|
||||
auto check = []<typename To>(To, auto m, auto cr)
|
||||
|
|
@ -381,7 +378,7 @@ template<template<size_t> typename Layout>
|
|||
|
||||
check(Layout<6>{}, msta, cnever);
|
||||
check(Layout<6>{}, mdyn, cnever);
|
||||
check(Layout<dyn>{}, msta, calways);
|
||||
check(Layout<dyn>{}, msta, cregular);
|
||||
check(Layout<dyn>{}, mdyn, cnever);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue