Hi, I do not think that the change is necessary, as for the functions default on the first declaration (as in the case for the constructors/assigments for mdpsan) have noexcept specifier deduced from it body. In other words, I think the test should pass, without adding the complicated noexcept conditions.
Regards, Tomasz On Fri, Jun 27, 2025 at 11:19 AM Luc Grosheintz <luc.groshei...@gmail.com> wrote: > If all members of mdspan are nothrow movable, then mdspan can also > be nothrow movable. The standard doesn't specify that mdspan must be > nothrow movable (when possible). Nothrow movable enables containers > to use move operations even if they have a strong exception guarantee. > > This commit strenghtens the exception guarantees for mdspan, making > it nothrow movable if all it's members are nothrow movable. > > libstdc++-v3/ChangeLog: > > * include/std/mdspan (mdspan): Make nothrow movable, if all > members are nothrow movable. > * testsuite/23_containers/mdspan/mdspan.cc: Test nothrow movable > property. > > Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com> > --- > libstdc++-v3/include/std/mdspan | 10 +++- > .../testsuite/23_containers/mdspan/mdspan.cc | 53 ++++++++++++++++++- > 2 files changed, 60 insertions(+), 3 deletions(-) > > diff --git a/libstdc++-v3/include/std/mdspan > b/libstdc++-v3/include/std/mdspan > index 852f881971e..563aa312f8a 100644 > --- a/libstdc++-v3/include/std/mdspan > +++ b/libstdc++-v3/include/std/mdspan > @@ -1119,7 +1119,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > mdspan(const mdspan& __other) = default; > > constexpr > - mdspan(mdspan&& __other) = default; > + mdspan(mdspan&& __other) > + noexcept(is_nothrow_move_constructible_v<accessor_type> > + && is_nothrow_move_constructible_v<mapping_type> > + && is_nothrow_move_constructible_v<data_handle_type>) = default; > > template<__mdspan::__valid_index_type<index_type>... _OIndexTypes> > requires ((sizeof...(_OIndexTypes) == rank() > @@ -1197,7 +1200,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > operator=(const mdspan& __other) = default; > > constexpr mdspan& > - operator=(mdspan&& __other) = default; > + operator=(mdspan&& __other) > + noexcept(is_nothrow_move_assignable_v<accessor_type> > + && is_nothrow_move_assignable_v<mapping_type> > + && is_nothrow_move_assignable_v<data_handle_type>) = default; > > template<__mdspan::__valid_index_type<index_type>... _OIndexTypes> > requires (sizeof...(_OIndexTypes) == rank()) > diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc > index d2672878d69..6d8f32ff103 100644 > --- a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc > @@ -310,11 +310,29 @@ test_from_int_like() > verify(std::mdspan(storage.data(), shape_view)); > } > > -template<typename T> > +template<typename T, bool NothrowConstructible = true, > + bool NothrowAssignable = true> > class OpaqueAccessor > { > struct Handle > { > + constexpr > + Handle(T * other) > + : ptr(other) > + { } > + > + constexpr > + Handle(const Handle&) noexcept(NothrowConstructible) = default; > + > + constexpr > + Handle(Handle&&) noexcept(NothrowConstructible) = default; > + > + constexpr Handle& > + operator=(const Handle&) noexcept(NothrowAssignable) = default; > + > + constexpr Handle& > + operator=(Handle&&) noexcept(NothrowAssignable) = default; > + > T * ptr; > }; > > @@ -489,6 +507,37 @@ test_swap() > return true; > } > > +template<bool Constructible, bool Assignable> > +constexpr void > +test_nothrow_movable() > +{ > + using Layout = std::layout_left; > + using Extents = std::dextents<int, 3>; > + using Accessor = OpaqueAccessor<int, Constructible, Assignable>; > + using Handle = Accessor::data_handle_type; > + static_assert(std::is_nothrow_move_assignable_v<Accessor>); > + static_assert(std::is_nothrow_move_constructible_v<Accessor>); > + static_assert(std::is_nothrow_move_assignable_v<Handle> == Assignable); > + static_assert(std::is_nothrow_move_constructible_v<Handle> == > Constructible); > + > + using MDSpan = std::mdspan<int, Extents, Layout, Accessor>; > + static_assert(std::is_nothrow_move_assignable_v<MDSpan> == Assignable); > + static_assert(std::is_nothrow_move_constructible_v<MDSpan> == > Constructible); > +} > + > +constexpr void > +test_nothrow_movable_all() > +{ > + using MDSpan = std::mdspan<double, std::dextents<int, 3>>; > + static_assert(std::is_nothrow_move_assignable_v<MDSpan>); > + static_assert(std::is_nothrow_move_constructible_v<MDSpan>); > + > + test_nothrow_movable<true, true>(); > + test_nothrow_movable<true, false>(); > + test_nothrow_movable<false, true>(); > + test_nothrow_movable<false, false>(); > +} > + > int > main() > { > @@ -536,5 +585,7 @@ main() > > test_swap(); > static_assert(test_swap()); > + > + test_nothrow_movable_all(); > return 0; > } > -- > 2.49.0 > >