https://gcc.gnu.org/g:dfab6593b05a65b5a475e0572e101bd56e3a2282
commit r16-2391-gdfab6593b05a65b5a475e0572e101bd56e3a2282 Author: Luc Grosheintz <luc.groshei...@gmail.com> Date: Mon Jul 21 13:07:37 2025 +0200 libstdc++: Make the default ctor of mdspan conditionally noexcept. Previously, the default ctor of mdspan was never noexcept, even if all members of mdspan were nothrow default constructible. This commit makes mdspan conditionally nothrow default constructible. A similar strengthening happens in libc++. libstdc++-v3/ChangeLog: * include/std/mdspan (mdspan::mdspan): Make default ctor conditionally noexcept. * testsuite/23_containers/mdspan/mdspan.cc: Add tests. Reviewed-by: Jonathan Wakely <jwak...@redhat.com> Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com> Diff: --- libstdc++-v3/include/std/mdspan | 12 +++---- .../testsuite/23_containers/mdspan/mdspan.cc | 37 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan index 89b9f3c8aba7..055778d29688 100644 --- a/libstdc++-v3/include/std/mdspan +++ b/libstdc++-v3/include/std/mdspan @@ -1114,11 +1114,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr mdspan() requires (rank_dynamic() > 0) - && is_default_constructible_v<data_handle_type> + && is_default_constructible_v<data_handle_type> && is_default_constructible_v<mapping_type> - && is_default_constructible_v<accessor_type> - : _M_accessor(), _M_mapping(), _M_handle() - { } + && is_default_constructible_v<accessor_type> = default; constexpr mdspan(const mdspan& __other) = default; @@ -1307,9 +1305,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION stride(rank_type __r) const { return _M_mapping.stride(__r); } private: - [[no_unique_address]] accessor_type _M_accessor; - [[no_unique_address]] mapping_type _M_mapping; - [[no_unique_address]] data_handle_type _M_handle; + [[no_unique_address]] accessor_type _M_accessor = accessor_type(); + [[no_unique_address]] mapping_type _M_mapping = mapping_type(); + [[no_unique_address]] data_handle_type _M_handle = data_handle_type(); }; template<typename _CArray> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc index 942f6d96dca7..6ffddd11e951 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc @@ -4,6 +4,7 @@ #include <testsuite_hooks.h> #include "int_like.h" #include "layout_like.h" +#include <stdexcept> constexpr auto dyn = std::dynamic_extent; @@ -114,6 +115,27 @@ test_class_properties_all() return true; } +template<typename T> + class ThrowingDefaultAccessor + { + public: + using element_type = T; + using reference = element_type&; + using data_handle_type = element_type*; + using offset_policy = ThrowingDefaultAccessor; + + ThrowingDefaultAccessor() noexcept(false) + { } + + reference + access(data_handle_type p, size_t i) const + { return p[i]; } + + typename offset_policy::data_handle_type + offset(data_handle_type p, size_t i) const + { return p + i; } + }; + constexpr bool test_default_ctor() { @@ -130,6 +152,18 @@ test_default_ctor() return true; } +template<template<typename T> typename Accessor, bool Expected> + constexpr void + test_nothrow_default_ctor() + { + using Extents = std::extents<int, dyn>; + using Layout = std::layout_left; + using MDSpan = std::mdspan<double, Extents, Layout, Accessor<double>>; + + static_assert(std::is_default_constructible_v<MDSpan>); + static_assert(std::is_nothrow_default_constructible_v<MDSpan> == Expected); + } + constexpr bool test_from_other() { @@ -683,6 +717,9 @@ main() test_default_ctor(); static_assert(test_default_ctor()); + test_nothrow_default_ctor<std::default_accessor, true>(); + test_nothrow_default_ctor<ThrowingDefaultAccessor, false>(); + test_from_other(); static_assert(test_from_other());