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

Reply via email to