diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 2fad249ec3..7e584e4c40 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -75,63 +75,24 @@ private: static constexpr array _Dynamic_indices = _Make_dynamic_indices(); _NODISCARD static consteval auto _Make_dynamic_indices_inv() noexcept { - array _Result{}; + array _Result{}; + rank_type _Counter = 0; for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) { - for (rank_type _Idx_inv = 0; _Idx_inv < _Rank; ++_Idx_inv) { - if (_Dynamic_indices[_Idx_inv + 1] == _Idx + 1) { - _Result[_Idx] = _Idx_inv; - break; - } + if (_Static_extents[_Idx] == dynamic_extent) { + _Analysis_assume_(_Counter < _Rank_dynamic); // TRANSITION, DevCom-923103 + _Result[_Counter] = _Idx; + ++_Counter; } } return _Result; } - static constexpr array _Dynamic_indices_inv = _Make_dynamic_indices_inv(); - - struct _Construct_from_tuple { - explicit _Construct_from_tuple() = default; - }; + static constexpr array _Dynamic_indices_inv = _Make_dynamic_indices_inv(); using _Base = _Maybe_empty_array<_IndexType, _Rank_dynamic>; -public: - _NODISCARD static constexpr rank_type rank() noexcept { - return _Rank; - } - - _NODISCARD static constexpr rank_type rank_dynamic() noexcept { - return _Rank_dynamic; - } - - _NODISCARD static constexpr size_t static_extent(const rank_type _Idx) noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Idx < _Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/1)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 - return _Static_extents[_Idx]; - } - - _NODISCARD constexpr index_type extent(const rank_type _Idx) const noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Idx < _Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/3)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 - if constexpr (rank_dynamic() == 0) { - return static_cast(_Static_extents[_Idx]); - } else if constexpr (rank_dynamic() == rank()) { - return this->_Array[_Idx]; - } else { - if (_Static_extents[_Idx] == dynamic_extent) { - return this->_Array[_Dynamic_indices[_Idx]]; - } else { - return static_cast(_Static_extents[_Idx]); - } - } - } - - constexpr extents() noexcept = default; - template - requires (sizeof...(_OtherExtents) == rank()) + requires (sizeof...(_OtherExtents) == _Rank) && ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...) constexpr explicit extents( const extents<_OtherIndexType, _OtherExtents...>& _Other, index_sequence<_Indices...>) noexcept @@ -153,21 +114,17 @@ public: #endif // _CONTAINER_DEBUG_LEVEL > 0 } - template - requires (sizeof...(_OtherExtents) == rank()) - && ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...) - constexpr explicit(((_Extents != dynamic_extent && _OtherExtents == dynamic_extent) || ...) - || (numeric_limits::max)() < (numeric_limits<_OtherIndexType>::max)()) - extents(const extents<_OtherIndexType, _OtherExtents...>& _Other) noexcept - : extents(_Other, make_index_sequence{}) {} + struct _Construct_from_tuple { + explicit _Construct_from_tuple() = default; + }; template - requires (tuple_size_v<_ExtsTuple> == rank_dynamic()) + requires (tuple_size_v<_ExtsTuple> == _Rank_dynamic) constexpr explicit extents(_Construct_from_tuple, _ExtsTuple _Tpl, index_sequence<_Indices...>) noexcept : _Base{static_cast(_STD move(_STD get<_Indices>(_Tpl)))...} {} template - requires (tuple_size_v<_ExtsTuple> != rank_dynamic()) + requires (tuple_size_v<_ExtsTuple> != _Rank_dynamic) constexpr explicit extents(_Construct_from_tuple, _ExtsTuple _Tpl, index_sequence<_DynIndices...>) noexcept : _Base{static_cast(_STD move(_STD get<_Dynamic_indices_inv[_DynIndices]>(_Tpl)))...} { #if _CONTAINER_DEBUG_LEVEL > 0 @@ -182,32 +139,9 @@ public: #endif // _CONTAINER_DEBUG_LEVEL > 0 } - template - requires (is_convertible_v<_OtherIndexTypes, index_type> && ...) - && (is_nothrow_constructible_v && ...) - && (sizeof...(_OtherIndexTypes) == rank_dynamic() || sizeof...(_OtherIndexTypes) == rank()) - constexpr explicit extents(_OtherIndexTypes... _Exts) noexcept - : extents(_Construct_from_tuple{}, _STD tie(_Exts...), make_index_sequence{}) { -#if _CONTAINER_DEBUG_LEVEL > 0 - auto _Check_extent = [](const _Ty& _Ext) { - if constexpr (_Is_standard_integer<_Ty>) { - return _Ext >= 0 && _STD in_range(_Ext); - } else if constexpr (integral<_Ty> && !same_as<_Ty, bool>) { // NB: character types - const auto _Integer_ext = static_cast(_Ext); - return _Integer_ext >= 0 && _STD in_range(_Integer_ext); - } else { - return true; // NB: We cannot check preconditions - } - }; - _STL_VERIFY((_Check_extent(_Exts) && ...), - "Either sizeof...(exts) must be equal to 0 or each element of exts must be nonnegative and must be " - "representable as value of type index_type (N4950 [mdspan.extents.cons]/7.2)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 - } - template requires is_convertible_v - && is_nothrow_constructible_v && (_Size == rank_dynamic()) + && is_nothrow_constructible_v && (_Size == _Rank_dynamic) constexpr explicit extents(span<_OtherIndexType, _Size> _Dynamic_exts, index_sequence<_Indices...>) noexcept : _Base{static_cast(_STD as_const(_Dynamic_exts[_Indices]))...} { #if _CONTAINER_DEBUG_LEVEL > 0 @@ -221,7 +155,7 @@ public: template requires is_convertible_v - && is_nothrow_constructible_v && (_Size != rank_dynamic()) + && is_nothrow_constructible_v && (_Size != _Rank_dynamic) constexpr explicit extents(span<_OtherIndexType, _Size> _Mixed_exts, index_sequence<_Indices...>) noexcept : _Base{static_cast(_STD as_const(_Mixed_exts[_Dynamic_indices_inv[_Indices]]))...} { #if _CONTAINER_DEBUG_LEVEL > 0 @@ -239,6 +173,72 @@ public: #endif // _CONTAINER_DEBUG_LEVEL > 0 } +public: + _NODISCARD static constexpr rank_type rank() noexcept { + return _Rank; + } + + _NODISCARD static constexpr rank_type rank_dynamic() noexcept { + return _Rank_dynamic; + } + + _NODISCARD static constexpr size_t static_extent(const rank_type _Idx) noexcept { +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(_Idx < _Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/1)"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 + return _Static_extents[_Idx]; + } + + _NODISCARD constexpr index_type extent(const rank_type _Idx) const noexcept { +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(_Idx < _Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/3)"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 + if constexpr (rank_dynamic() == 0) { + return static_cast(_Static_extents[_Idx]); + } else if constexpr (rank_dynamic() == rank()) { + return this->_Array[_Idx]; + } else { + if (_Static_extents[_Idx] == dynamic_extent) { + return this->_Array[_Dynamic_indices[_Idx]]; + } else { + return static_cast(_Static_extents[_Idx]); + } + } + } + + constexpr extents() noexcept = default; + + template + requires (sizeof...(_OtherExtents) == rank()) + && ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...) + constexpr explicit(((_Extents != dynamic_extent && _OtherExtents == dynamic_extent) || ...) + || (numeric_limits::max)() < (numeric_limits<_OtherIndexType>::max)()) + extents(const extents<_OtherIndexType, _OtherExtents...>& _Other) noexcept + : extents(_Other, make_index_sequence{}) {} + + template + requires (is_convertible_v<_OtherIndexTypes, index_type> && ...) + && (is_nothrow_constructible_v && ...) + && (sizeof...(_OtherIndexTypes) == rank_dynamic() || sizeof...(_OtherIndexTypes) == rank()) + constexpr explicit extents(_OtherIndexTypes... _Exts) noexcept + : extents(_Construct_from_tuple{}, _STD tie(_Exts...), make_index_sequence{}) { +#if _CONTAINER_DEBUG_LEVEL > 0 + auto _Check_extent = [](const _Ty& _Ext) { + if constexpr (_Is_standard_integer<_Ty>) { + return _Ext >= 0 && _STD in_range(_Ext); + } else if constexpr (integral<_Ty> && !same_as<_Ty, bool>) { // NB: character types + const auto _Integer_ext = static_cast(_Ext); + return _Integer_ext >= 0 && _STD in_range(_Integer_ext); + } else { + return true; // NB: We cannot check preconditions + } + }; + _STL_VERIFY((_Check_extent(_Exts) && ...), + "Either sizeof...(exts) must be equal to 0 or each element of exts must be nonnegative and must be " + "representable as value of type index_type (N4950 [mdspan.extents.cons]/7.2)"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 + } + template requires is_convertible_v && is_nothrow_constructible_v @@ -342,9 +342,10 @@ template inline constexpr bool _Is_extents> = true; template - requires _Is_extents<_Extents> class _Fwd_prod_of_extents { public: + _STL_INTERNAL_STATIC_ASSERT(_Is_extents<_Extents>); + _NODISCARD static constexpr _Extents::index_type _Calculate(const _Extents& _Exts, const size_t _Idx) noexcept { _STL_INTERNAL_CHECK(_Idx <= _Extents::_Rank); if constexpr (_Extents::rank() == 0) { @@ -359,34 +360,36 @@ public: } }; -template - requires (sizeof...(_Extents) > 0) && ((_Extents != dynamic_extent) && ...) -class _Fwd_prod_of_extents> { +template + requires (_Extents::rank() > 0) && (_Extents::rank_dynamic() == 0) +class _Fwd_prod_of_extents<_Extents> { private: - using _Ty = extents<_IndexType, _Extents...>; + _STL_INTERNAL_STATIC_ASSERT(_Is_extents<_Extents>); _NODISCARD static consteval auto _Make_prods() noexcept { - array _Result; + array _Result; _Result.front() = 1; - for (size_t _Idx = 1; _Idx < _Ty::_Rank + 1; ++_Idx) { - _Result[_Idx] = static_cast<_Ty::index_type>(_Result[_Idx - 1] * _Ty::_Static_extents[_Idx - 1]); + for (size_t _Idx = 1; _Idx < _Extents::_Rank + 1; ++_Idx) { + _Result[_Idx] = static_cast<_Extents::index_type>(_Result[_Idx - 1] * _Extents::_Static_extents[_Idx - 1]); } return _Result; } - static constexpr array _Cache = _Make_prods(); + static constexpr array _Cache = _Make_prods(); public: - _NODISCARD static constexpr _Ty::index_type _Calculate(const _Ty&, const size_t _Idx) noexcept { - _STL_INTERNAL_CHECK(_Idx <= _Ty::_Rank); + _NODISCARD static constexpr _Extents::index_type _Calculate(const _Extents&, const size_t _Idx) noexcept { + _STL_INTERNAL_CHECK(_Idx <= _Extents::_Rank); return _Cache[_Idx]; } }; template - requires _Is_extents<_Extents> && (_Extents::rank() > 0) class _Rev_prod_of_extents { public: + _STL_INTERNAL_STATIC_ASSERT(_Is_extents<_Extents>); + _STL_INTERNAL_STATIC_ASSERT(_Extents::rank() > 0); + _NODISCARD static constexpr _Extents::index_type _Calculate(const _Extents& _Exts, const size_t _Idx) noexcept { _STL_INTERNAL_CHECK(_Idx < _Extents::_Rank); typename _Extents::index_type _Result = 1; @@ -397,26 +400,27 @@ public: } }; -template - requires ((_Extents != dynamic_extent) && ...) -class _Rev_prod_of_extents> { +template + requires (_Extents::rank_dynamic() == 0) +class _Rev_prod_of_extents<_Extents> { private: - using _Ty = extents<_IndexType, _Extents...>; + _STL_INTERNAL_STATIC_ASSERT(_Is_extents<_Extents>); + _STL_INTERNAL_STATIC_ASSERT(_Extents::rank() > 0); _NODISCARD static consteval auto _Make_prods() noexcept { - array _Result; + array _Result; _Result.back() = 1; - for (size_t _Idx = _Ty::_Rank; _Idx-- > 1;) { - _Result[_Idx - 1] = static_cast<_Ty::index_type>(_Result[_Idx] * _Ty::_Static_extents[_Idx]); + for (size_t _Idx = _Extents::_Rank; _Idx-- > 1;) { + _Result[_Idx - 1] = static_cast<_Extents::index_type>(_Result[_Idx] * _Extents::_Static_extents[_Idx]); } return _Result; } - static constexpr array _Cache = _Make_prods(); + static constexpr array _Cache = _Make_prods(); public: - _NODISCARD static constexpr _Ty::index_type _Calculate(const _Ty&, const size_t _Idx) noexcept { - _STL_INTERNAL_CHECK(_Idx < _Ty::_Rank); + _NODISCARD static constexpr _Extents::index_type _Calculate(const _Extents&, const size_t _Idx) noexcept { + _STL_INTERNAL_CHECK(_Idx < _Extents::_Rank); return _Cache[_Idx]; } }; @@ -528,7 +532,8 @@ public: template requires is_constructible_v - constexpr explicit(extents_type::rank() > 0) mapping(const layout_stride::template mapping<_OtherExtents>& _Other) + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::template mapping<_OtherExtents>& _Other) noexcept // strengthened : _Base(_Other.extents()) { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (extents_type::rank() > 0) { @@ -814,8 +819,8 @@ public: const bool _Overflow = _Mul_overflow(this->_Array[_Idx + 1], this->_Exts.extent(_Idx + 1), this->_Array[_Idx]); // NB: N4950 requires value of 'layout_right::mapping().required_span_size()' to be - // representable as value of type 'index_type', but this is not enough. We need to require every single - // stride to be representable as value of type 'index_type', so we can get desired effects. + // representable as a value of type 'index_type', but this is not enough. We need to require every + // single stride to be representable as a value of type 'index_type', so we can get desired effects. _STL_VERIFY(!_Overflow, "Value of layout_right::mapping().required_span_size() must be " "representable as a value of type index_type (N4950 [mdspan.layout.stride.cons]/1)."); @@ -1185,7 +1190,9 @@ public: return this->_Map.extents().extent(_Idx); } - constexpr mdspan() + constexpr mdspan() noexcept( + is_nothrow_default_constructible_v&& is_nothrow_default_constructible_v&& + is_nothrow_default_constructible_v) // strengthened requires (rank_dynamic() > 0) && is_default_constructible_v && is_default_constructible_v && is_default_constructible_v {} @@ -1198,7 +1205,9 @@ public: && (is_nothrow_constructible_v && ...) && (sizeof...(_OtherIndexTypes) == rank() || sizeof...(_OtherIndexTypes) == rank_dynamic()) && is_constructible_v && is_default_constructible_v - constexpr explicit mdspan(data_handle_type _Ptr_, _OtherIndexTypes... _Exts) + constexpr explicit mdspan(data_handle_type _Ptr_, _OtherIndexTypes... _Exts) noexcept( + is_nothrow_move_constructible_v&& is_nothrow_constructible_v&& + is_nothrow_default_constructible_v) // strengthened : _Mapping_base(extents_type{static_cast(_STD move(_Exts))...}), _Accessor_base(), _Ptr(_STD move(_Ptr_)) {} @@ -1207,7 +1216,10 @@ public: && is_nothrow_constructible_v && (_Size == rank() || _Size == rank_dynamic()) && is_constructible_v && is_default_constructible_v - constexpr explicit(_Size != rank_dynamic()) mdspan(data_handle_type _Ptr_, span<_OtherIndexType, _Size> _Exts) + constexpr explicit(_Size != rank_dynamic()) + mdspan(data_handle_type _Ptr_, span<_OtherIndexType, _Size> _Exts) noexcept( + is_nothrow_move_constructible_v&& is_nothrow_constructible_v&& + is_nothrow_default_constructible_v) // strengthened : _Mapping_base(extents_type{_Exts}), _Accessor_base(), _Ptr(_STD move(_Ptr_)) {} template @@ -1216,18 +1228,26 @@ public: && (_Size == rank() || _Size == rank_dynamic()) && is_constructible_v && is_default_constructible_v constexpr explicit(_Size != rank_dynamic()) - mdspan(data_handle_type _Ptr_, const array<_OtherIndexType, _Size>& _Exts) + mdspan(data_handle_type _Ptr_, const array<_OtherIndexType, _Size>& _Exts) noexcept( + is_nothrow_move_constructible_v&& is_nothrow_constructible_v&& + is_nothrow_default_constructible_v) // strengthened : _Mapping_base(extents_type{_Exts}), _Accessor_base(), _Ptr(_STD move(_Ptr_)) {} - constexpr mdspan(data_handle_type _Ptr_, const extents_type& _Exts) + constexpr mdspan(data_handle_type _Ptr_, const extents_type& _Exts) noexcept( + is_nothrow_move_constructible_v&& is_nothrow_constructible_v&& is_nothrow_default_constructible_v) // strengthened requires is_constructible_v && is_default_constructible_v : _Mapping_base(_Exts), _Accessor_base(), _Ptr(_STD move(_Ptr_)) {} - constexpr mdspan(data_handle_type _Ptr_, const mapping_type& _Map_) + constexpr mdspan(data_handle_type _Ptr_, const mapping_type& _Map_) noexcept( + is_nothrow_move_constructible_v&& is_nothrow_copy_constructible_v&& + is_nothrow_default_constructible_v) // strengthened requires is_default_constructible_v : _Mapping_base(_Map_), _Accessor_base(), _Ptr(_STD move(_Ptr_)) {} - constexpr mdspan(data_handle_type _Ptr_, const mapping_type& _Map_, const accessor_type& _Acc_) + constexpr mdspan(data_handle_type _Ptr_, const mapping_type& _Map_, const accessor_type& _Acc_) noexcept( + is_nothrow_move_constructible_v&& is_nothrow_copy_constructible_v&& + is_nothrow_copy_constructible_v) // strengthened : _Mapping_base(_Map_), _Accessor_base(_Acc_), _Ptr(_STD move(_Ptr_)) {} template @@ -1236,7 +1256,11 @@ public: constexpr explicit( !is_convertible_v&, mapping_type> || !is_convertible_v) - mdspan(const mdspan<_OtherElementType, _OtherExtents, _OtherLayoutPolicy, _OtherAccessor>& _Other) + mdspan(const mdspan<_OtherElementType, _OtherExtents, _OtherLayoutPolicy, _OtherAccessor>& _Other) noexcept( + is_nothrow_constructible_v&& + is_nothrow_constructible_v&>&& + is_nothrow_constructible_v) // strengthened : _Mapping_base(_Other.mapping()), _Accessor_base(_Other.accessor()), _Ptr(_Other.data_handle()) { static_assert(is_constructible_v, "The data_handle_type must be constructible from const typename OtherAccessor::data_handle_type& (N4950 " @@ -1261,7 +1285,8 @@ public: requires (is_convertible_v<_OtherIndexTypes, index_type> && ...) && (is_nothrow_constructible_v && ...) && (sizeof...(_OtherIndexTypes) == rank()) - _NODISCARD constexpr reference operator[](_OtherIndexTypes... _Indices) const { + _NODISCARD constexpr reference operator[](_OtherIndexTypes... _Indices) const + noexcept(noexcept(_Access_impl(static_cast(_STD move(_Indices))...))) /* strengthened */ { return _Access_impl(static_cast(_STD move(_Indices))...); } #endif // __cpp_multidimensional_subscript @@ -1387,7 +1412,8 @@ private: #endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ template - _NODISCARD constexpr reference _Access_impl(_OtherIndexTypes... _Indices) const { + _NODISCARD constexpr reference _Access_impl(_OtherIndexTypes... _Indices) const + noexcept(noexcept(this->_Acc.access(_Ptr, static_cast(this->_Map(_Indices...))))) /* strengthened */ { _STL_INTERNAL_STATIC_ASSERT((same_as<_OtherIndexTypes, index_type> && ...)); #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Map.extents()._Contains_multidimensional_index(make_index_sequence{}, _Indices...), diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index 80ac1e4daf..9a49ebe6d4 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -229,9 +229,9 @@ constexpr void check_members_with_various_extents(Fn&& fn) { details::check_members_with_various_extents_impl(std::forward(fn), std::make_index_sequence<2>{}); details::check_members_with_various_extents_impl(std::forward(fn), std::make_index_sequence<4>{}); details::check_members_with_various_extents_impl(std::forward(fn), std::make_index_sequence<8>{}); -#ifndef _PREFAST_ - details::check_members_with_various_extents_impl(std::forward(fn), std::make_index_sequence<16>{}); -#endif // _PREFAST_ + if (!std::is_constant_evaluated()) { + details::check_members_with_various_extents_impl(std::forward(fn), std::make_index_sequence<16>{}); + } } namespace details { diff --git a/tests/std/tests/GH_002206_unreserved_names/test.compile.pass.cpp b/tests/std/tests/GH_002206_unreserved_names/test.compile.pass.cpp index 7bed2d659c..c57279e236 100644 --- a/tests/std/tests/GH_002206_unreserved_names/test.compile.pass.cpp +++ b/tests/std/tests/GH_002206_unreserved_names/test.compile.pass.cpp @@ -39,4 +39,4 @@ #if empty_bases != 6 #error bad macro expansion -#endif // noop_dtor != 6 +#endif // empty_bases != 6 diff --git a/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp b/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp index 4a506e77c0..30c743c087 100644 --- a/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp @@ -55,7 +55,7 @@ void test_construction_from_pack_with_unrepresentable_as_index_type_values_2() { } void test_construction_from_pack_with_unrepresentable_as_index_type_values_3() { - static_assert(signed_integral, "char is not signed integral"); + static_assert(signed_integral, "This test assumes that it isn't being compiled with /J"); // Either sizeof...(exts) must be equal to 0 or each element of exts must be nonnegative and must be representable // as value of type index_type [[maybe_unused]] extents e{static_cast(-1)}; diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index 4c53b23742..0073f773cc 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -84,9 +84,6 @@ constexpr void check_members(const extents& ext, index_se // Other tests are defined in 'check_construction_from_other_right_mapping' function } -#ifdef __clang__ - if (!is_constant_evaluated()) // FIXME clang hits constexpr limit here -#endif { // Check construction from layout_stride::mapping array strides{}; if constexpr (Ext::rank() > 0) { @@ -261,14 +258,14 @@ constexpr void check_construction_from_other_right_mapping() { constexpr void check_construction_from_other_stride_mapping() { { // Check construction from layout_stride::mapping with various values of E::rank() - static_assert( - is_constructible_v>, layout_stride::mapping>>); - static_assert( - is_constructible_v>, layout_stride::mapping>>); - static_assert( - is_constructible_v>, layout_stride::mapping>>); - static_assert( - is_constructible_v>, layout_stride::mapping>>); + static_assert(is_nothrow_constructible_v>, + layout_stride::mapping>>); // strengthened + static_assert(is_nothrow_constructible_v>, + layout_stride::mapping>>); // strengthened + static_assert(is_nothrow_constructible_v>, + layout_stride::mapping>>); // strengthened + static_assert(is_nothrow_constructible_v>, + layout_stride::mapping>>); // strengthened } { // Check construction from layout_stride::mapping when E is invalid @@ -423,10 +420,6 @@ constexpr void check_correctness() { #endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ } - -#ifdef __clang__ - if (!is_constant_evaluated()) // FIXME clang hits constexpr limit here -#endif { // 3x2 matrix with column-major order const array values{0, 1, 2, 3, 4, 5}; mdspan, layout_left> matrix{values.data()}; @@ -448,9 +441,6 @@ constexpr void check_correctness() { #endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ } -#ifdef __clang__ - if (!is_constant_evaluated()) // FIXME clang hits constexpr limit here -#endif { // 3x2x4 tensor const array values{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; mdspan, layout_left> tensor{values.data(), 3, 2, 4}; @@ -472,9 +462,6 @@ constexpr void check_correctness() { #endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ } -#ifdef __clang__ - if (!is_constant_evaluated()) // FIXME clang hits constexpr limit here -#endif { // 2x3x2x3 tensor const array values{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35}; diff --git a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp index 273a461ecf..87babc454c 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp @@ -33,9 +33,6 @@ constexpr void check_members(const extents& ext, index_se static_assert(same_as); static_assert(same_as); -#ifdef __clang__ - if (!is_constant_evaluated()) // FIXME clang hits constexpr limit here -#endif { // Check default and copy constructor const Mapping m; Mapping cpy = m; @@ -63,9 +60,6 @@ constexpr void check_members(const extents& ext, index_se using Ext2 = extents; using Mapping2 = layout_right::mapping; -#ifdef __clang__ - if (!is_constant_evaluated()) // FIXME clang hits constexpr limit here -#endif { // Check construction from other layout_right::mapping Mapping m1{ext}; Mapping2 m2{m1}; diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp index c8a0b9b1d1..ed2e78c199 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp @@ -15,7 +15,7 @@ using namespace std; void test_default_construction() { using Ext = extents; - // Value of layout_right::mapping().required_span_size() must be + // Value of layout_stride::mapping().required_span_size() must be // representable as a value of type index_type [[maybe_unused]] layout_stride::mapping m{}; // NB: strides are [140, 35, 7, 1] } diff --git a/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp b/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp index aa4915c84c..48a2e2d07e 100644 --- a/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp @@ -397,13 +397,14 @@ constexpr void check_observers() { constexpr void check_default_constructor() { { // Check constraint: 'rank_dynamic() > 0' - static_assert(is_default_constructible_v>>); + static_assert(is_nothrow_default_constructible_v>>); // strengthened static_assert(!is_default_constructible_v>>); static_assert(!is_default_constructible_v>>); } { // Check constraints: 'is_default_constructible_v' - static_assert(is_default_constructible_v, layout_right, VectorBoolAccessor>>); + static_assert(is_nothrow_default_constructible_v< + mdspan, layout_right, VectorBoolAccessor>>); // strengthened static_assert( !is_default_constructible_v, layout_right, TrackingAccessor>>); } @@ -414,8 +415,8 @@ constexpr void check_default_constructor() { } { // Check constraint: 'is_default_constructible_v' - static_assert(is_default_constructible_v< - mdspan, layout_right, AccessorWithCustomOffsetPolicy>>); + static_assert(is_nothrow_default_constructible_v< + mdspan, layout_right, AccessorWithCustomOffsetPolicy>>); // strengthened static_assert( !is_default_constructible_v, layout_right, TrackingAccessor>>); } @@ -455,36 +456,40 @@ constexpr void check_defaulted_copy_and_move_constructors() { constexpr void check_data_handle_and_indices_pack_constructor() { { // Check constraint: '(is_convertible_v && ...)' using Mds = mdspan>; - static_assert(is_constructible_v); - static_assert(is_constructible_v); - static_assert(is_constructible_v); - static_assert(is_constructible_v>); + static_assert(is_nothrow_constructible_v); // strengthened + static_assert(is_nothrow_constructible_v); // strengthened + static_assert( + is_nothrow_constructible_v); // strengthened + static_assert(is_nothrow_constructible_v>); // strengthened static_assert(!is_constructible_v); } { // Check constraint: '(is_nothrow_constructible && ...)' using Mds = mdspan>; - static_assert(is_constructible_v>); + static_assert(is_nothrow_constructible_v>); // strengthened static_assert(!is_constructible_v>); } { // Check constraint: 'N == rank() || N == rank_dynamic()' using Mds = mdspan>; static_assert(!is_constructible_v); - static_assert(is_constructible_v); + static_assert(is_nothrow_constructible_v); // strengthened static_assert(!is_constructible_v); - static_assert(is_constructible_v); + static_assert(is_nothrow_constructible_v); // strengthened } { // Check constraint: 'is_constructible_v' - static_assert(is_constructible_v, layout_left>, int* const, int, int>); + static_assert(is_nothrow_constructible_v, layout_left>, int* const, int, + int>); // strengthened static_assert(!is_constructible_v, layout_stride>, int*, int, int>); static_assert(!is_constructible_v, TrackingLayout<>>, int*, int, int>); } { // Check constraint: 'is_default_constructible_v' - static_assert(is_constructible_v, layout_right, VectorBoolAccessor>, - vector::iterator, int, int>); + static_assert(is_nothrow_constructible_v, layout_right, VectorBoolAccessor>, + vector::iterator, int, int>); // strengthened static_assert( !is_constructible_v, layout_right, TrackingAccessor>, int*, int, int>); } @@ -537,18 +542,20 @@ constexpr void check_data_handle_and_indices_pack_constructor() { constexpr void check_data_handle_and_span_array_constructors() { { // Check constraint: 'is_convertible_v' using Mds = mdspan>; - static_assert(is_constructible_v>); - static_assert(is_constructible_v>); - static_assert(is_constructible_v, 3>>); - static_assert(is_constructible_v, 3>>); + static_assert(is_nothrow_constructible_v>); // strengthened + static_assert(is_nothrow_constructible_v>); // strengthened + static_assert(is_nothrow_constructible_v, 3>>); // strengthened + static_assert(is_nothrow_constructible_v, 3>>); // strengthened static_assert(!is_constructible_v>); static_assert(!is_constructible_v>); } { // Check constraint: 'is_nothrow_constructible' using Mds = mdspan>; - static_assert(is_constructible_v, 2>>); - static_assert(is_constructible_v, 2>>); + static_assert(is_nothrow_constructible_v, 2>>); // strengthened + static_assert(is_nothrow_constructible_v, 2>>); // strengthened static_assert(!is_constructible_v, 2>>); static_assert(!is_constructible_v, 2>>); } @@ -557,23 +564,31 @@ constexpr void check_data_handle_and_span_array_constructors() { using Mds = mdspan>; static_assert(!is_constructible_v>); static_assert(!is_constructible_v>); - static_assert(is_constructible_v>); - static_assert(is_constructible_v>); + static_assert(is_nothrow_constructible_v>); // strengthened + static_assert(is_nothrow_constructible_v>); // strengthened static_assert(!is_constructible_v>); static_assert(!is_constructible_v>); - static_assert(is_constructible_v>); - static_assert(is_constructible_v>); + static_assert(is_nothrow_constructible_v>); // strengthened + static_assert(is_nothrow_constructible_v>); // strengthened } { // Check constraint: 'is_constructible_v' - static_assert(is_constructible_v, layout_left>, int* const, span>); - static_assert(is_constructible_v, layout_left>, int* const, array>); + static_assert(is_nothrow_constructible_v, layout_left>, int* const, + span>); // strengthened + static_assert(is_nothrow_constructible_v, layout_left>, int* const, + array>); // strengthened static_assert( is_constructible_v, TrackingLayout>, int* const, span>); + static_assert( + !is_nothrow_constructible_v, TrackingLayout>, + int* const, span>); // strengthened static_assert( is_constructible_v, TrackingLayout>, int* const, array>); + static_assert( + !is_nothrow_constructible_v, TrackingLayout>, + int* const, array>); // strengthened static_assert(!is_constructible_v, layout_stride>, int*, span>); static_assert(!is_constructible_v, layout_stride>, int*, array>); static_assert(!is_constructible_v, TrackingLayout<>>, int*, span>); @@ -581,10 +596,10 @@ constexpr void check_data_handle_and_span_array_constructors() { } { // Check constraint: 'is_default_constructible_v' - static_assert(is_constructible_v, layout_right, VectorBoolAccessor>, - vector::iterator, span>); - static_assert(is_constructible_v, layout_right, VectorBoolAccessor>, - vector::iterator, array>); + static_assert(is_nothrow_constructible_v, layout_right, VectorBoolAccessor>, + vector::iterator, span>); // strengthened + static_assert(is_nothrow_constructible_v, layout_right, VectorBoolAccessor>, + vector::iterator, array>); // strengthened static_assert(!is_constructible_v, layout_right, TrackingAccessor>, int*, span>); static_assert(!is_constructible_v, layout_right, TrackingAccessor>, int*, @@ -658,18 +673,20 @@ constexpr void check_data_handle_and_span_array_constructors() { constexpr void check_data_handle_and_extents_constructor() { { // Check constraint: 'is_constructible_v' - static_assert(is_constructible_v>, int*, dextents>); - static_assert(is_constructible_v>, int*, dextents>); + static_assert( + is_nothrow_constructible_v>, int*, dextents>); // strengthened + static_assert( + is_nothrow_constructible_v>, int*, dextents>); // strengthened static_assert(!is_constructible_v, layout_stride>, int*, dextents>); static_assert(!is_constructible_v>, int*, dextents>); static_assert(!is_constructible_v>, int*, extents>); } { // Check constraint: is_default_constructible_v - static_assert(is_constructible_v, layout_right, VectorBoolAccessor>, - vector::iterator, dextents>); - static_assert(is_constructible_v, layout_right, VectorBoolAccessor>, - vector::iterator, extents>); + static_assert(is_nothrow_constructible_v, layout_right, VectorBoolAccessor>, + vector::iterator, dextents>); // strengthened + static_assert(is_nothrow_constructible_v, layout_right, VectorBoolAccessor>, + vector::iterator, extents>); // strengthened static_assert(!is_constructible_v, layout_right, TrackingAccessor>, int*, dextents>); static_assert(!is_constructible_v, layout_right, TrackingAccessor>, int*, @@ -699,10 +716,10 @@ constexpr void check_data_handle_and_extents_constructor() { constexpr void check_data_handle_and_mapping_constructor() { { // Check constraint: 'is_default_constructible_v' - static_assert(is_constructible_v, layout_left, VectorBoolAccessor>, - vector::iterator, layout_left::mapping>>); - static_assert(is_constructible_v, layout_left>, int* const, - layout_left::mapping>>); + static_assert(is_nothrow_constructible_v, layout_left, VectorBoolAccessor>, + vector::iterator, layout_left::mapping>>); // strengthened + static_assert(is_nothrow_constructible_v, layout_left>, int* const, + layout_left::mapping>>); // strengthened static_assert(!is_constructible_v< mdspan, extents, TrackingLayout<>, TrackingAccessor>>, vector*, TrackingLayout<>::mapping>>); @@ -736,30 +753,42 @@ constexpr void check_data_handle_and_mapping_constructor() { } constexpr void check_data_handle_and_mapping_and_accessor_constructor() { - using Ext = extents; - using Mds = mdspan, TrackingAccessor>; - - unsigned int identity_matrix[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; - Mds mds{TrackingDataHandle{16, identity_matrix}, TrackingLayout<>::mapping(17), - TrackingAccessor{18}}; - - // Check effects: - // - Direct-non-list-initializes ptr_ with std::move(p), - // - direct-non-list-initializes map_ with m, and - // - direct-non-list-initializes acc_ with a. - assert(mds.data_handle().is_move_constructed()); - assert(mds.data_handle().get_id() == 16); - assert(mds.mapping().is_copy_constructed()); - assert(mds.mapping().get_id() == 17); - assert(mds.accessor().is_copy_constructed()); - assert(mds.accessor().get_id() == 18); + { // Check effects + using Ext = extents; + using Mds = mdspan, TrackingAccessor>; + + unsigned int identity_matrix[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; + Mds mds{TrackingDataHandle{16, identity_matrix}, TrackingLayout<>::mapping(17), + TrackingAccessor{18}}; + + // Effects: + // - Direct-non-list-initializes ptr_ with std::move(p), + // - direct-non-list-initializes map_ with m, and + // - direct-non-list-initializes acc_ with a. + assert(mds.data_handle().is_move_constructed()); + assert(mds.data_handle().get_id() == 16); + assert(mds.mapping().is_copy_constructed()); + assert(mds.mapping().get_id() == 17); + assert(mds.accessor().is_copy_constructed()); + assert(mds.accessor().get_id() == 18); + } + + { // Check noexceptness (strengthened) + using Mds1 = mdspan>; + static_assert(is_nothrow_constructible_v); + + using Mds2 = mdspan, TrackingLayout<>>; + static_assert(!is_nothrow_constructible_v); + } } constexpr void check_construction_from_other_mdspan() { { // Check constraint: 'is_constructible_v&>' - static_assert(is_constructible_v, layout_stride>, - mdspan, layout_right>>); + static_assert(is_nothrow_constructible_v, layout_stride>, + mdspan, layout_right>>); // strengthened static_assert(!is_constructible_v, layout_left>, mdspan, layout_right>>); static_assert(!is_constructible_v, layout_left>, @@ -768,8 +797,9 @@ constexpr void check_construction_from_other_mdspan() { { // Check constraint: 'is_constructible_v' using Ext = extents; - static_assert(is_constructible_v>, - mdspan>>); + static_assert( + is_nothrow_constructible_v>, + mdspan>>); // strengthened static_assert(!is_constructible_v>, mdspan>>); } @@ -877,6 +907,11 @@ constexpr void check_multidimensional_subscript_operator() { assert(r1); same_as::reference> decltype(auto) r2 = as_const(mds)[0, 1]; assert(!r2); + +#ifndef __clang__ // TRANSITION, Clang 17 + static_assert(noexcept(mds[1, 1])); // strengthened + static_assert(noexcept(as_const(mds)[0, 1])); // strengthened +#endif // __clang__ } { // Check that indices are moved and then casted to 'index_type' @@ -1334,7 +1369,7 @@ constexpr void check_deduction_guides() { } // When -// * 'Mds::accessor_type' is specialization of 'default_accesor', and +// * 'Mds::accessor_type' is a specialization of 'default_accessor', and // * 'Mds::layout_type' is // * 'layout_left' or 'layout_right' and 'Mds::extents_type::rank_dynamic() == 0', or // * 'layout_stride' and 'Mds::extents_type::rank() == 0' diff --git a/tests/std/tests/P0009R18_mdspan_mdspan_death/test.cpp b/tests/std/tests/P0009R18_mdspan_mdspan_death/test.cpp index 76398b5cc5..f4c072422c 100644 --- a/tests/std/tests/P0009R18_mdspan_mdspan_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_mdspan_death/test.cpp @@ -13,7 +13,7 @@ using namespace std; constexpr array some_ints{}; void test_construction_from_other_mdspan() { - auto mds1 = mdspan{some_ints.data(), 8, 2, 8}; + mdspan mds1{some_ints.data(), 8, 2, 8}; // For each rank index r of extents_type, static_extent(r) == dynamic_extent || static_extent(r) == other.extent(r) // must be true [[maybe_unused]] mdspan> mds2{mds1}; @@ -21,26 +21,26 @@ void test_construction_from_other_mdspan() { #ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6 void test_access_with_invalid_multidimensional_index_1() { - auto mds = mdspan{some_ints.data(), 4, 4}; + mdspan mds{some_ints.data(), 4, 4}; // I must be a multidimensional index in extents() (void) mds[3, 4]; } #endif // __cpp_multidimensional_subscript void test_access_with_invalid_multidimensional_index_2() { - auto mds = mdspan{some_ints.data(), 5, 5}; + mdspan mds{some_ints.data(), 5, 5}; // I must be a multidimensional index in extents() (void) mds[array{4, 5}]; } void test_size_when_index_type_is_signed() { - auto mds = mdspan{some_ints.data(), dextents{8, 8, 4}}; + mdspan mds{some_ints.data(), dextents{8, 8, 4}}; // The size of the multidimensional index space extents() must be representable as a value of type size_type (void) mds.size(); } void test_size_when_index_type_is_unsigned() { - auto mds = mdspan{some_ints.data(), dextents{8, 8, 4}}; + mdspan mds{some_ints.data(), dextents{8, 8, 4}}; // The size of the multidimensional index space extents() must be representable as a value of type size_type (void) mds.size(); }