From 3177a962ac78933403bcf84e0d9d06ac20adaff7 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Sun, 28 May 2023 22:43:53 +0200 Subject: [PATCH 01/13] Implement extra internal checks in `_(Fwd/Rev)_prod_of_extents` and: * Rename some `_Dim` variables to `_Idx` * Fix constraints on `_Fwd_prod_of_extents` (don't create static array when `rank() == 0`) --- stl/inc/mdspan | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index bd7420639aa..20951d60854 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -280,6 +280,7 @@ template class _Fwd_prod_of_extents { public: _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) { return 1; } else { @@ -293,7 +294,7 @@ public: }; template - requires ((_Extents != dynamic_extent) && ...) + requires (sizeof...(_Extents) > 0) && ((_Extents != dynamic_extent) && ...) class _Fwd_prod_of_extents> { private: using _Ty = extents<_IndexType, _Extents...>; @@ -301,8 +302,8 @@ private: _NODISCARD static consteval auto _Make_prods() noexcept { array _Result; _Result.front() = 1; - for (size_t _Dim = 1; _Dim < _Ty::_Rank + 1; ++_Dim) { - _Result[_Dim] = static_cast<_Ty::index_type>(_Result[_Dim - 1] * _Ty::static_extent(_Dim - 1)); + for (size_t _Idx = 1; _Idx < _Ty::_Rank + 1; ++_Idx) { + _Result[_Idx] = static_cast<_Ty::index_type>(_Result[_Idx - 1] * _Ty::static_extent(_Idx - 1)); } return _Result; } @@ -311,6 +312,7 @@ private: public: _NODISCARD static constexpr _Ty::index_type _Calculate(const _Ty&, const size_t _Idx) noexcept { + _STL_INTERNAL_CHECK(_Idx <= _Ty::_Rank); return _Cache[_Idx]; } }; @@ -320,6 +322,7 @@ template class _Rev_prod_of_extents { public: _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; for (size_t _Dim = _Idx + 1; _Dim < _Extents::_Rank; ++_Dim) { _Result *= _Exts.extent(_Dim); @@ -337,8 +340,8 @@ private: _NODISCARD static consteval auto _Make_prods() noexcept { array _Result; _Result.back() = 1; - for (size_t _Dim = _Ty::_Rank; _Dim-- > 1;) { - _Result[_Dim - 1] = static_cast<_Ty::index_type>(_Result[_Dim] * _Ty::static_extent(_Dim)); + for (size_t _Idx = _Ty::_Rank; _Idx-- > 1;) { + _Result[_Idx - 1] = static_cast<_Ty::index_type>(_Result[_Idx] * _Ty::static_extent(_Idx)); } return _Result; } @@ -347,6 +350,7 @@ private: public: _NODISCARD static constexpr _Ty::index_type _Calculate(const _Ty&, const size_t _Idx) noexcept { + _STL_INTERNAL_CHECK(_Idx < _Ty::_Rank); return _Cache[_Idx]; } }; From 2248ae720b619eec0efd60f9528b0a4a7f8c255e Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Sun, 28 May 2023 22:25:23 +0200 Subject: [PATCH 02/13] Make `extents(array/span)` constructor a little bit more efficient and rename its parameters --- stl/inc/mdspan | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 20951d60854..88913173bab 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -172,11 +172,11 @@ public: template requires is_convertible_v - && is_nothrow_constructible_v && (_Size != rank()) - constexpr explicit extents(span<_OtherIndexType, _Size> _Exts, index_sequence<_Indices...>) noexcept - : _Dynamic_extents{static_cast(_STD as_const(_Exts[_Indices]))...} { + && is_nothrow_constructible_v && (_Size == rank_dynamic()) + constexpr explicit extents(span<_OtherIndexType, _Size> _Dynamic_exts, index_sequence<_Indices...>) noexcept + : _Dynamic_extents{static_cast(_STD as_const(_Dynamic_exts[_Indices]))...} { if constexpr (_Is_standard_integer<_OtherIndexType> && _Size != 0) { - for (_OtherIndexType _Ext : _Exts) { + for (_OtherIndexType _Ext : _Dynamic_exts) { _STL_VERIFY(_Ext >= 0 && _STD in_range(_Ext), "Either N must be zero or exts[r] must be nonnegative and must be representable as value of type " "index_type for every rank index r (N4950 [mdspan.extents.cons]/10.2)"); @@ -186,16 +186,16 @@ public: template requires is_convertible_v - && is_nothrow_constructible_v && (_Size == rank()) - constexpr explicit extents(span<_OtherIndexType, _Size> _Exts, index_sequence<_Indices...>) noexcept - : _Dynamic_extents{static_cast(_STD as_const(_Exts[_Dynamic_indices_inv[_Indices]]))...} { + && is_nothrow_constructible_v && (_Size != rank_dynamic()) + constexpr explicit extents(span<_OtherIndexType, _Size> _Mixed_exts, index_sequence<_Indices...>) noexcept + : _Dynamic_extents{static_cast(_STD as_const(_Mixed_exts[_Dynamic_indices_inv[_Indices]]))...} { if constexpr (_Is_standard_integer<_OtherIndexType>) { for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) { _STL_VERIFY( - _Static_extents[_Idx] == dynamic_extent || _STD cmp_equal(_Static_extents[_Idx], _Exts[_Idx]), + _Static_extents[_Idx] == dynamic_extent || _STD cmp_equal(_Static_extents[_Idx], _Mixed_exts[_Idx]), "Value of exts[r] must be equal to extent(r) for each r for which extent(r) is a static extent " "(N4950 [mdspan.extents.cons]/10.1)"); - _STL_VERIFY(_Exts[_Idx] >= 0 && _STD in_range(_Exts[_Idx]), + _STL_VERIFY(_Mixed_exts[_Idx] >= 0 && _STD in_range(_Mixed_exts[_Idx]), "Either N must be zero or exts[r] must be nonnegative and must be representable as value of type " "index_type for every rank index r (N4950 [mdspan.extents.cons]/10.2)"); } From e76155db64f2669235f76e14eb8d133abce9fd76 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 16 Jun 2023 14:01:32 +0200 Subject: [PATCH 03/13] Improve checks in `extents(indices...)` constructor --- stl/inc/mdspan | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 88913173bab..1af5da3fb7f 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -146,11 +146,18 @@ public: && (is_nothrow_constructible_v && ...) && (sizeof...(_OtherIndexTypes) == rank_dynamic() || sizeof...(_OtherIndexTypes) == rank()) constexpr explicit extents(_OtherIndexTypes... _Exts) noexcept { - if constexpr ((_Is_standard_integer<_OtherIndexTypes> && ...)) { - _STL_VERIFY(sizeof...(_Exts) == 0 || ((_Exts >= 0 && _STD in_range(_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)"); - } + auto _Check_extent = [](const _Ty& _Ext) { + if constexpr (_Is_standard_integer<_Ty>) { + return _Ext >= 0 && _STD in_range(_Ext); + } else if constexpr (_Integer_like<_Ty>) { + return _Ext >= 0; + } 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)"); if constexpr (sizeof...(_Exts) == rank_dynamic()) { _Dynamic_extents = {static_cast(_STD move(_Exts))...}; From 9f980f48f04eff8a023b72abf04f545a09c40701 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 19 Jun 2023 15:19:49 +0200 Subject: [PATCH 04/13] Drive-by: add parentheses around `std::min` in `test_mdspan_support.hpp` --- tests/std/include/test_mdspan_support.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index b653d74268e..c6c1f034fa0 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -177,7 +177,7 @@ namespace details { template constexpr void check_members_with_mixed_extents(Fn&& fn) { auto select_extent = [](size_t e) consteval { - return e == std::dynamic_extent ? std::min(sizeof...(Extents), size_t{3}) : e; + return e == std::dynamic_extent ? (std::min)(sizeof...(Extents), size_t{3}) : e; }; // Check signed integers @@ -198,7 +198,7 @@ namespace details { template constexpr void check_members_with_various_extents_impl(Fn&& fn, std::index_sequence) { auto static_or_dynamic = [](size_t i) consteval { - return i == 0 ? std::dynamic_extent : std::min(sizeof...(Seq), size_t{3}); + return i == 0 ? std::dynamic_extent : (std::min)(sizeof...(Seq), size_t{3}); }; if constexpr (sizeof...(Seq) <= 1) { From 56a1058550ddb9577c68f74f2106933149048d5b Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 19 Jun 2023 15:24:46 +0200 Subject: [PATCH 05/13] Improve `extent(other extents)` constructor --- stl/inc/mdspan | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 1af5da3fb7f..7af13535fcf 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -118,29 +118,35 @@ public: constexpr extents() noexcept = default; - template + 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 { - auto _It = _Dynamic_extents.begin(); - for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) { - _STL_VERIFY( - _Static_extents[_Idx] == dynamic_extent || _STD cmp_equal(_Static_extents[_Idx], _Other.extent(_Idx)), - "Value of other.extent(r) must be equal to extent(r) for each r for which extent(r) is a static extent " - "(N4950 [mdspan.extents.cons]/2.1)"); - _STL_VERIFY(_STD in_range(_Other.extent(_Idx)), - "Value of other.extent(r) must be representable as a value of type index_type for every rank index r " - "(N4950 [mdspan.extents.cons]/2.2)"); - - if (_Static_extents[_Idx] == dynamic_extent) { - *_It = static_cast(_Other.extent(_Idx)); - ++_It; + constexpr explicit extents( + const extents<_OtherIndexType, _OtherExtents...>& _Other, index_sequence<_Indices...>) noexcept + : _Dynamic_extents{static_cast(_Other.extent(_Dynamic_indices_inv[_Indices]))...} { + if constexpr (rank() > 0) { + for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) { + if constexpr (rank() != rank_dynamic()) { + _STL_VERIFY(_Static_extents[_Idx] == dynamic_extent + || _STD cmp_equal(_Static_extents[_Idx], _Other.extent(_Idx)), + "Value of other.extent(r) must be equal to extent(r) for each r for which extent(r) is a " + "static extent (N4950 [mdspan.extents.cons]/2.1)"); + } + _STL_VERIFY(_STD in_range(_Other.extent(_Idx)), + "Value of other.extent(r) must be representable as a value of type index_type for every rank index " + "r (N4950 [mdspan.extents.cons]/2.2)"); } } } + 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 && ...) From 0f22be9041009d371161d5f5946d01f6df021626 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 19 Jun 2023 15:56:13 +0200 Subject: [PATCH 06/13] Improve `extents(indices...)` constructor --- stl/inc/mdspan | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 7af13535fcf..40e4034adb7 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -14,6 +14,7 @@ _EMIT_STL_WARNING(STL4038, "The contents of are available only with C++ #include #include #include +#include #include #pragma pack(push, _CRT_PACKING) @@ -74,6 +75,8 @@ private: static constexpr array _Dynamic_indices_inv = _Make_dynamic_indices_inv(); + struct _Construct_from_tuple {}; + struct _Static_extents_only { constexpr explicit _Static_extents_only() noexcept = default; @@ -147,11 +150,31 @@ public: extents(const extents<_OtherIndexType, _OtherExtents...>& _Other) noexcept : extents(_Other, make_index_sequence{}) {} + template + requires (tuple_size_v<_ExtsTuple> == rank_dynamic()) + constexpr explicit extents(_Construct_from_tuple, _ExtsTuple _Tpl, index_sequence<_Indices...>) noexcept + : _Dynamic_extents{static_cast(_STD move(_STD get<_Indices>(_Tpl)))...} {} + + template + requires (tuple_size_v<_ExtsTuple> != rank_dynamic()) + constexpr explicit extents(_Construct_from_tuple, _ExtsTuple _Tpl, index_sequence<_DynIndices...>) noexcept + : _Dynamic_extents{static_cast(_STD move(_STD get<_Dynamic_indices_inv[_DynIndices]>(_Tpl)))...} { + [&](index_sequence<_MixedIndices...>) { + _STL_VERIFY(((_Static_extents[_MixedIndices] == dynamic_extent + || _STD cmp_equal(_Static_extents[_MixedIndices], + static_cast(_STD move(_STD get<_MixedIndices>(_Tpl))))) + && ...), + "Value of exts_arr[r] must be equal to extent(r) for each r for which extent(r) is a static extent " + "(N4950 [mdspan.extents.cons]/7.1)"); + }(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 { + constexpr explicit extents(_OtherIndexTypes... _Exts) noexcept + : extents(_Construct_from_tuple{}, _STD tie(_Exts...), make_index_sequence{}) { auto _Check_extent = [](const _Ty& _Ext) { if constexpr (_Is_standard_integer<_Ty>) { return _Ext >= 0 && _STD in_range(_Ext); @@ -164,23 +187,6 @@ public: _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)"); - - if constexpr (sizeof...(_Exts) == rank_dynamic()) { - _Dynamic_extents = {static_cast(_STD move(_Exts))...}; - } else { - array _Exts_arr{static_cast(_STD move(_Exts))...}; - auto _It = _Dynamic_extents.begin(); - for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) { - _STL_VERIFY( - _Static_extents[_Idx] == dynamic_extent || _STD cmp_equal(_Static_extents[_Idx], _Exts_arr[_Idx]), - "Value of exts_arr[r] must be equal to extent(r) for each r for which extent(r) is a static extent " - "(N4950 [mdspan.extents.cons]/7.1)"); - if (_Static_extents[_Idx] == dynamic_extent) { - *_It = _Exts_arr[_Idx]; - ++_It; - } - } - } } template From d20371e285186a96ca130776140d82c0ef6f8fdd Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 19 Jun 2023 15:59:43 +0200 Subject: [PATCH 07/13] Avoid another `for` loop --- stl/inc/mdspan | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 40e4034adb7..7878834619a 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -195,11 +195,9 @@ public: constexpr explicit extents(span<_OtherIndexType, _Size> _Dynamic_exts, index_sequence<_Indices...>) noexcept : _Dynamic_extents{static_cast(_STD as_const(_Dynamic_exts[_Indices]))...} { if constexpr (_Is_standard_integer<_OtherIndexType> && _Size != 0) { - for (_OtherIndexType _Ext : _Dynamic_exts) { - _STL_VERIFY(_Ext >= 0 && _STD in_range(_Ext), - "Either N must be zero or exts[r] must be nonnegative and must be representable as value of type " - "index_type for every rank index r (N4950 [mdspan.extents.cons]/10.2)"); - } + _STL_VERIFY(((_Dynamic_exts[_Indices] >= 0 && _STD in_range(_Dynamic_exts[_Indices])) && ...), + "Either N must be zero or exts[r] must be nonnegative and must be representable as value of type " + "index_type for every rank index r (N4950 [mdspan.extents.cons]/10.2)"); } } From 2f587d5d1c54917252597537be8969f5b55cdf86 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 19 Jun 2023 16:06:41 +0200 Subject: [PATCH 08/13] Use `_CONTAINER_DEBUG_LEVEL` to guard debug checks --- stl/inc/mdspan | 14 ++++++++++++++ .../tests/P0009R18_mdspan_extents_death/test.cpp | 2 ++ 2 files changed, 16 insertions(+) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 7878834619a..7db94ee22cd 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -100,12 +100,16 @@ public: } _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()) { @@ -127,6 +131,7 @@ public: constexpr explicit extents( const extents<_OtherIndexType, _OtherExtents...>& _Other, index_sequence<_Indices...>) noexcept : _Dynamic_extents{static_cast(_Other.extent(_Dynamic_indices_inv[_Indices]))...} { +#if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (rank() > 0) { for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) { if constexpr (rank() != rank_dynamic()) { @@ -140,6 +145,7 @@ public: "r (N4950 [mdspan.extents.cons]/2.2)"); } } +#endif // _CONTAINER_DEBUG_LEVEL > 0 } template @@ -159,6 +165,7 @@ public: requires (tuple_size_v<_ExtsTuple> != rank_dynamic()) constexpr explicit extents(_Construct_from_tuple, _ExtsTuple _Tpl, index_sequence<_DynIndices...>) noexcept : _Dynamic_extents{static_cast(_STD move(_STD get<_Dynamic_indices_inv[_DynIndices]>(_Tpl)))...} { +#if _CONTAINER_DEBUG_LEVEL > 0 [&](index_sequence<_MixedIndices...>) { _STL_VERIFY(((_Static_extents[_MixedIndices] == dynamic_extent || _STD cmp_equal(_Static_extents[_MixedIndices], @@ -167,6 +174,7 @@ public: "Value of exts_arr[r] must be equal to extent(r) for each r for which extent(r) is a static extent " "(N4950 [mdspan.extents.cons]/7.1)"); }(make_index_sequence{}); +#endif // _CONTAINER_DEBUG_LEVEL > 0 } template @@ -175,6 +183,7 @@ public: && (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); @@ -187,6 +196,7 @@ public: _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 @@ -194,11 +204,13 @@ public: && is_nothrow_constructible_v && (_Size == rank_dynamic()) constexpr explicit extents(span<_OtherIndexType, _Size> _Dynamic_exts, index_sequence<_Indices...>) noexcept : _Dynamic_extents{static_cast(_STD as_const(_Dynamic_exts[_Indices]))...} { +#if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (_Is_standard_integer<_OtherIndexType> && _Size != 0) { _STL_VERIFY(((_Dynamic_exts[_Indices] >= 0 && _STD in_range(_Dynamic_exts[_Indices])) && ...), "Either N must be zero or exts[r] must be nonnegative and must be representable as value of type " "index_type for every rank index r (N4950 [mdspan.extents.cons]/10.2)"); } +#endif // _CONTAINER_DEBUG_LEVEL > 0 } template @@ -206,6 +218,7 @@ public: && is_nothrow_constructible_v && (_Size != rank_dynamic()) constexpr explicit extents(span<_OtherIndexType, _Size> _Mixed_exts, index_sequence<_Indices...>) noexcept : _Dynamic_extents{static_cast(_STD as_const(_Mixed_exts[_Dynamic_indices_inv[_Indices]]))...} { +#if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (_Is_standard_integer<_OtherIndexType>) { for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) { _STL_VERIFY( @@ -217,6 +230,7 @@ public: "index_type for every rank index r (N4950 [mdspan.extents.cons]/10.2)"); } } +#endif // _CONTAINER_DEBUG_LEVEL > 0 } template diff --git a/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp b/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp index 2c80d249ab3..ccdf5bff78b 100644 --- a/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#define _CONTAINER_DEBUG_LEVEL 1 + #include #include #include From fb0c9aae20bb9a517e9ce9ffb4a59c65fbad6af4 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 19 Jun 2023 16:11:44 +0200 Subject: [PATCH 09/13] Dead code: integer-like classes cannot be used as an argument to `extents(indices...)` constructor --- stl/inc/mdspan | 2 -- 1 file changed, 2 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 7db94ee22cd..f9501f9c825 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -187,8 +187,6 @@ public: auto _Check_extent = [](const _Ty& _Ext) { if constexpr (_Is_standard_integer<_Ty>) { return _Ext >= 0 && _STD in_range(_Ext); - } else if constexpr (_Integer_like<_Ty>) { - return _Ext >= 0; } else { return true; // NB: We cannot check preconditions } From 8e777be202865ff920091813488fef6709775f0e Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 19 Jun 2023 16:13:03 +0200 Subject: [PATCH 10/13] Extra death test for `extents` --- .../std/tests/P0009R18_mdspan_extents_death/test.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp b/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp index ccdf5bff78b..78e3e9ad2ad 100644 --- a/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp @@ -9,6 +9,7 @@ #include #include +#include using namespace std; @@ -41,12 +42,18 @@ void test_construction_from_pack_with_invalid_values() { [[maybe_unused]] extents e{1, 1}; } -void test_construction_from_pack_with_unrepresentable_as_index_type_values() { +void test_construction_from_pack_with_unrepresentable_as_index_type_values_1() { // 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{1, 256}; } +void test_construction_from_pack_with_unrepresentable_as_index_type_values_2() { + // 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{ConvertibleToInt{.val = 1}, 256}; +} + void test_construction_from_span_with_invalid_values() { int vals[] = {1, 2}; span s{vals}; @@ -84,7 +91,8 @@ int main(int argc, char* argv[]) { test_construction_from_other_extents_with_invalid_values, test_construction_from_other_extents_with_unrepresentable_as_index_type_values, test_construction_from_pack_with_invalid_values, - test_construction_from_pack_with_unrepresentable_as_index_type_values, + test_construction_from_pack_with_unrepresentable_as_index_type_values_1, + test_construction_from_pack_with_unrepresentable_as_index_type_values_2, test_construction_from_span_with_invalid_values, test_construction_from_span_with_unrepresentable_as_index_type_values, test_construction_from_array_with_invalid_values, From d3cff2da597c5b125e7ca9df45f77c59a00fe2f6 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 19 Jun 2023 16:18:39 +0200 Subject: [PATCH 11/13] Add explicit defaulted constructor to `_Construct_from_tuple` tag type --- stl/inc/mdspan | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index f9501f9c825..7f1dbd5f035 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -75,7 +75,9 @@ private: static constexpr array _Dynamic_indices_inv = _Make_dynamic_indices_inv(); - struct _Construct_from_tuple {}; + struct _Construct_from_tuple { + constexpr explicit _Construct_from_tuple() noexcept = default; + }; struct _Static_extents_only { constexpr explicit _Static_extents_only() noexcept = default; From b9ff0518926d9aa8234bd43450c862779f925eb9 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 19 Jun 2023 16:19:41 +0200 Subject: [PATCH 12/13] Remove unnecessary members of `_Static_extents_only` type --- stl/inc/mdspan | 7 ------- 1 file changed, 7 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 7f1dbd5f035..65bcadb4cb6 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -81,13 +81,6 @@ private: struct _Static_extents_only { constexpr explicit _Static_extents_only() noexcept = default; - - template - constexpr explicit _Static_extents_only(_Args&&...) noexcept {} - - _NODISCARD constexpr index_type* begin() const noexcept { - return nullptr; - } }; conditional_t<_Rank_dynamic != 0, array, _Static_extents_only> _Dynamic_extents{}; From ed8b639daae77672765dd4deb9c141eb95418f82 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 19 Jun 2023 22:07:12 +0200 Subject: [PATCH 13/13] Poke CI