diff --git a/stl/inc/mdspan b/stl/inc/mdspan index a603de5f0b2..d956cb23431 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), + "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)); +} +#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, });