The mdspan::is_{,always}_{unique,strided,exhaustive} methods only call their counterparts in mdspan::mapping_type. The standard specifies that the methods of mdspan::mapping_type are noexcept, but doesn't specify if the methods of mdspan are noexcept.
Libc++ strengthened the exception guarantee for these mdspan methods. This commit conditionally strengthens these methods for libstdc++. libstdc++-v3/ChangeLog: * include/std/mdspan (mdspan::is_always_unique): Make conditionally noexcept. (mdspan::is_always_exhaustive): Ditto. (mdspan::is_always_strided): Ditto. (mdspan::is_unique): Ditto. (mdspan::is_exhaustive): Ditto. (mdspan::is_strided): Ditto. * testsuite/23_containers/mdspan/layout_like.h: Make noexcept configurable. Add ThrowingLayout. * testsuite/23_containers/mdspan/mdspan.cc: Add tests for noexcept. Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com> --- libstdc++-v3/include/std/mdspan | 21 ++- .../23_containers/mdspan/layout_like.h | 134 +++++++++--------- .../testsuite/23_containers/mdspan/mdspan.cc | 17 +++ 3 files changed, 101 insertions(+), 71 deletions(-) diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan index 271fdb5d8c7..f71141f43a9 100644 --- a/libstdc++-v3/include/std/mdspan +++ b/libstdc++-v3/include/std/mdspan @@ -1275,23 +1275,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr const accessor_type& accessor() const noexcept { return _M_accessor; } + // Strengthened noexcept for all `is_*` methods. static constexpr bool - is_always_unique() { return mapping_type::is_always_unique(); } + is_always_unique() noexcept(noexcept(mapping_type::is_always_unique())) + { return mapping_type::is_always_unique(); } static constexpr bool - is_always_exhaustive() { return mapping_type::is_always_exhaustive(); } + is_always_exhaustive() + noexcept(noexcept(mapping_type::is_always_exhaustive())) + { return mapping_type::is_always_exhaustive(); } static constexpr bool - is_always_strided() { return mapping_type::is_always_strided(); } + is_always_strided() + noexcept(noexcept(mapping_type::is_always_strided())) + { return mapping_type::is_always_strided(); } constexpr bool - is_unique() const { return _M_mapping.is_unique(); } + is_unique() const noexcept(noexcept(_M_mapping.is_unique())) + { return _M_mapping.is_unique(); } constexpr bool - is_exhaustive() const { return _M_mapping.is_exhaustive(); } + is_exhaustive() const noexcept(noexcept(_M_mapping.is_exhaustive())) + { return _M_mapping.is_exhaustive(); } constexpr bool - is_strided() const { return _M_mapping. is_strided(); } + is_strided() const noexcept(noexcept(_M_mapping.is_strided())) + { return _M_mapping. is_strided(); } constexpr index_type stride(rank_type __r) const { return _M_mapping.stride(__r); } diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h b/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h index 6a0f8cafaa7..ded6e9d0cc9 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h @@ -1,83 +1,87 @@ #ifndef TEST_MDSPAN_LAYOUT_LIKE_H #define TEST_MDSPAN_LAYOUT_LIKE_H 1 -struct LayoutLike -{ - template<typename Extents> - class mapping - { - public: - using extents_type = Extents; - using index_type = typename extents_type::index_type; - using size_type = typename extents_type::size_type; - using rank_type = typename extents_type::rank_type; - using layout_type = LayoutLike; - - constexpr - mapping() noexcept = default; - - constexpr - mapping(Extents exts) - : m_exts(exts) - { } - - constexpr const extents_type& - extents() const noexcept { return m_exts; } - - constexpr index_type - required_span_size() const noexcept +template<bool Noexcept> + struct CustomLayout + { + template<typename Extents> + class mapping { - for (size_t i = 0; i < extents_type::rank(); ++i) - if (m_exts.extent(i) == 0) - return 0; - return 1; - } - - template<typename... Indices> - requires (sizeof...(Indices) == extents_type::rank()) + public: + using extents_type = Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = CustomLayout; + + constexpr + mapping() noexcept = default; + + constexpr + mapping(Extents exts) + : m_exts(exts) + { } + + constexpr const extents_type& + extents() const noexcept(Noexcept) { return m_exts; } + constexpr index_type - operator()(Indices...) const noexcept + required_span_size() const noexcept(Noexcept) + { + for (size_t i = 0; i < extents_type::rank(); ++i) + if (m_exts.extent(i) == 0) + return 0; + return 1; + } + + template<typename... Indices> + requires (sizeof...(Indices) == extents_type::rank()) + constexpr index_type + operator()(Indices...) const noexcept(Noexcept) + { return 0; } + + static constexpr index_type + stride(rank_type) noexcept(Noexcept) { return 0; } - static constexpr index_type - stride(rank_type) noexcept - { return 0; } + static constexpr bool + is_always_unique() noexcept(Noexcept) + { return false; } - static constexpr bool - is_always_unique() noexcept - { return false; } + static constexpr bool + is_always_exhaustive() noexcept(Noexcept) + { return true; } - static constexpr bool - is_always_exhaustive() noexcept - { return true; } + static constexpr bool + is_always_strided() noexcept(Noexcept) + { return true; } - static constexpr bool - is_always_strided() noexcept - { return true; } + constexpr bool + is_unique() const noexcept(Noexcept) + { + if (required_span_size() == 0) + return true; - constexpr bool - is_unique() noexcept - { - if (required_span_size() == 0) + for (size_t i = 0; i < extents_type::rank(); ++i) + if (m_exts.extent(i) > 1) + return false; return true; + } - for (size_t i = 0; i < extents_type::rank(); ++i) - if (m_exts.extent(i) > 1) - return false; - return true; - } + static constexpr bool + is_exhaustive() noexcept(Noexcept) + { return true; } - static constexpr bool - is_exhaustive() noexcept - { return true; } + static constexpr bool + is_strided() noexcept(Noexcept) + { return true; } - static constexpr bool - is_strided() noexcept - { return true; } + private: + Extents m_exts; + }; + }; - private: - Extents m_exts; - }; -}; +using LayoutLike = CustomLayout<true>; +using ThrowingLayout = CustomLayout<false>; #endif diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc index be4a1b1c17e..942f6d96dca 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc @@ -650,6 +650,21 @@ test_nothrow_movable_all() test_nothrow_movable<false, false>(); } +template<typename Layout, bool Expected> + constexpr void + test_nothrow_is_methods() + { + using Extents = std::extents<int, dyn>; + using MDSpan = std::mdspan<double, Extents, Layout>; + static_assert(noexcept(MDSpan::is_always_unique()) == Expected); + static_assert(noexcept(MDSpan::is_always_exhaustive()) == Expected); + static_assert(noexcept(MDSpan::is_always_strided()) == Expected); + + static_assert(noexcept(std::declval<MDSpan>().is_unique()) == Expected); + static_assert(noexcept(std::declval<MDSpan>().is_exhaustive()) == Expected); + static_assert(noexcept(std::declval<MDSpan>().is_strided()) == Expected); + } + int main() { @@ -713,5 +728,7 @@ main() test_swap_adl(); test_nothrow_movable_all(); + test_nothrow_is_methods<std::layout_right, true>(); + test_nothrow_is_methods<ThrowingLayout, false>(); return 0; } -- 2.50.0