]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Strengthen exception guarantee for mdspan methods.
authorLuc Grosheintz <luc.grosheintz@gmail.com>
Mon, 21 Jul 2025 11:07:36 +0000 (13:07 +0200)
committerTomasz Kamiński <tkaminsk@redhat.com>
Mon, 21 Jul 2025 15:45:37 +0000 (17:45 +0200)
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.

Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Luc Grosheintz <luc.grosheintz@gmail.com>
libstdc++-v3/include/std/mdspan
libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h
libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc

index 271fdb5d8c7d7bfccc5d38d33246d89d8ac16add..89b9f3c8aba7b27079e7bfdb1b659536a23b44f7 100644 (file)
@@ -1275,23 +1275,33 @@ _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); }
index 6a0f8cafaa7904226f13c69d935bb8dbf24f3059..ded6e9d0cc907cc1a35cd0ba6f22bfeaf267fab2 100644 (file)
@@ -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
index be4a1b1c17e48ed24b82a401f1a1ff5182e35acc..942f6d96dca7c4ef75db67f809be0600474419ac 100644 (file)
@@ -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;
 }