From a82957c60b7a618d225b53a61289d3ac15051641 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 23 Nov 2023 00:06:03 +0800 Subject: [PATCH 1/2] Check preconditions of `mdspan::operator[]` clarified by LWG-3974 --- stl/inc/mdspan | 24 +++++++++++++++++++ .../P0009R18_mdspan_mdspan_death/test.cpp | 12 ++++++++++ 2 files changed, 36 insertions(+) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index a603de5f0b2..500ffebf343 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1131,6 +1131,22 @@ struct _Mdspan_accessor_base<_AccessorPolicy> { static constexpr _AccessorPolicy _Acc{}; }; +#if _CONTAINER_DEBUG_LEVEL > 0 +template +_NODISCARD constexpr _IndexType _Mdspan_checked_index_cast(_OtherIndexType&& _Idx) noexcept( + is_nothrow_constructible_v<_IndexType, _OtherIndexType>) { + _STL_INTERNAL_STATIC_ASSERT(is_integral_v<_IndexType> && is_constructible_v<_IndexType, _OtherIndexType>); + + using _Arg_value_t = remove_cvref_t<_OtherIndexType>; + if constexpr (is_integral_v<_Arg_value_t> && !is_same_v<_Arg_value_t, bool>) { + _STL_VERIFY(_STD in_range<_IndexType>(_Idx), + "The index must be representable by index_type in order to be in a valid " + "multidimensional index (N4964 [mdspan.mdspan.members]/3)."); + } + return static_cast<_IndexType>(_STD forward<_OtherIndexType>(_Idx)); +} +#endif // _CONTAINER_DEBUG_LEVEL > 0 + _EXPORT_STD template > class __declspec(empty_bases) mdspan : private _Mdspan_mapping_base<_Extents, _LayoutPolicy>, @@ -1278,7 +1294,11 @@ public: && (sizeof...(_OtherIndexTypes) == rank()) _NODISCARD constexpr reference operator[](_OtherIndexTypes... _Indices) const noexcept(noexcept(_Access_impl(static_cast(_STD move(_Indices))...))) /* strengthened */ { +#if _CONTAINER_DEBUG_LEVEL > 0 + return _Access_impl(_STD _Mdspan_checked_index_cast(_STD move(_Indices))...); +#else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL <= 0 vvv return _Access_impl(static_cast(_STD move(_Indices))...); +#endif // ^^^ _CONTAINER_DEBUG_LEVEL <= 0 ^^^ } #endif // ^^^ defined(__cpp_multidimensional_subscript) ^^^ @@ -1287,7 +1307,11 @@ private: _NODISCARD constexpr reference _Multidimensional_subscript( span<_OtherIndexType, rank()> _Indices, index_sequence<_Seq...>) const noexcept(noexcept(_Access_impl(static_cast(_STD as_const(_Indices[_Seq]))...))) { +#if _CONTAINER_DEBUG_LEVEL > 0 + return _Access_impl(_STD _Mdspan_checked_index_cast(_STD as_const(_Indices[_Seq]))...); +#else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL <= 0 vvv return _Access_impl(static_cast(_STD as_const(_Indices[_Seq]))...); +#endif // ^^^ _CONTAINER_DEBUG_LEVEL <= 0 ^^^ } public: diff --git a/tests/std/tests/P0009R18_mdspan_mdspan_death/test.cpp b/tests/std/tests/P0009R18_mdspan_mdspan_death/test.cpp index f4c072422c4..e1c3bba1a91 100644 --- a/tests/std/tests/P0009R18_mdspan_mdspan_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_mdspan_death/test.cpp @@ -25,6 +25,11 @@ void test_access_with_invalid_multidimensional_index_1() { // I must be a multidimensional index in extents() (void) mds[3, 4]; } + +void test_access_with_nonrepresentable_index_1() { + mdspan mds{some_ints.data(), dextents{2, 3}}; + (void) mds[256u, -255]; +} #endif // __cpp_multidimensional_subscript void test_access_with_invalid_multidimensional_index_2() { @@ -33,6 +38,11 @@ void test_access_with_invalid_multidimensional_index_2() { (void) mds[array{4, 5}]; } +void test_access_with_nonrepresentable_index_2() { + mdspan mds{some_ints.data(), dextents{2, 3}}; + (void) mds[array{256, -255}]; +} + void test_size_when_index_type_is_signed() { 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 @@ -51,8 +61,10 @@ int main(int argc, char* argv[]) { test_construction_from_other_mdspan, #ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6 test_access_with_invalid_multidimensional_index_1, + test_access_with_nonrepresentable_index_1, #endif // __cpp_multidimensional_subscript test_access_with_invalid_multidimensional_index_2, + test_access_with_nonrepresentable_index_2, test_size_when_index_type_is_signed, test_size_when_index_type_is_unsigned, }); From bdca33b5272be04ad37160c33b83e9f3ce98622c Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Mon, 27 Nov 2023 17:58:54 -0800 Subject: [PATCH 2/2] Update stl/inc/mdspan Clarify `static_assert` message. --- stl/inc/mdspan | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 500ffebf343..d956cb23431 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1140,8 +1140,8 @@ _NODISCARD constexpr _IndexType _Mdspan_checked_index_cast(_OtherIndexType&& _Id using _Arg_value_t = remove_cvref_t<_OtherIndexType>; if constexpr (is_integral_v<_Arg_value_t> && !is_same_v<_Arg_value_t, bool>) { _STL_VERIFY(_STD in_range<_IndexType>(_Idx), - "The index must be representable by index_type in order to be in a valid " - "multidimensional index (N4964 [mdspan.mdspan.members]/3)."); + "Each argument to operator[] must be representable by index_type in order for the pack of arguments to be " + "a valid multidimensional index (N4964 [mdspan.mdspan.members]/3)."); } return static_cast<_IndexType>(_STD forward<_OtherIndexType>(_Idx)); }