[gcc r16-2390] libstdc++: Strengthen exception guarantee for mdspan methods.
Tomasz Kaminski
tkaminsk@gcc.gnu.org
Mon Jul 21 15:47:23 GMT 2025
https://gcc.gnu.org/g:03437196942b03eee4f3f3edfaf201f5bdc37d9e
commit r16-2390-g03437196942b03eee4f3f3edfaf201f5bdc37d9e
Author: Luc Grosheintz <luc.grosheintz@gmail.com>
Date: Mon Jul 21 13:07:36 2025 +0200
libstdc++: Strengthen exception guarantee for mdspan methods.
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>
Diff:
---
libstdc++-v3/include/std/mdspan | 22 +++-
.../testsuite/23_containers/mdspan/layout_like.h | 134 +++++++++++----------
.../testsuite/23_containers/mdspan/mdspan.cc | 17 +++
3 files changed, 102 insertions(+), 71 deletions(-)
diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index 271fdb5d8c7d..89b9f3c8aba7 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -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); }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h b/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h
index 6a0f8cafaa79..ded6e9d0cc90 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 be4a1b1c17e4..942f6d96dca7 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;
}
More information about the Libstdc++-cvs
mailing list