On Mon, 21 Jul 2025, 12:08 Luc Grosheintz, <luc.groshei...@gmail.com> wrote:
> 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. > I have a slight preference for a blank like after this comment, because it applies to several following members, not just the first one. Without the blank like it looks like it's just a comment on the first one. Of course, if you actually read the comment you realise it applies to them all :-) OK for trunk anyway. 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 > >