diff --git a/stl/inc/ranges b/stl/inc/ranges index 6a5238a58f..0a89c81f9c 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -9991,11 +9991,14 @@ namespace ranges { { return [&](index_sequence<_Indices...>) { #if _CONTAINER_DEBUG_LEVEL > 0 + const array _Sizes = {static_cast<_Size_type>(_RANGES size(_STD get<_Indices>(_Bases)))...}; + const bool _Any_zero = ((_Sizes[_Indices] == 0) || ...); + if (_Any_zero) { + return _Size_type{0}; + } + _Size_type _Product{1}; - const bool _Overflow = - (_Mul_overflow( - _Product, static_cast<_Size_type>(_RANGES size(_STD get<_Indices>(_Bases))), _Product) - || ...); + const bool _Overflow = (_Mul_overflow(_Product, _Sizes[_Indices], _Product) || ...); _STL_VERIFY(!_Overflow, "Size of cartesian product cannot be represented by size type (N4950 " "[range.cartesian.view]/10)."); return _Product; @@ -10010,11 +10013,14 @@ namespace ranges { { return [&](index_sequence<_Indices...>) { #if _CONTAINER_DEBUG_LEVEL > 0 + const array _Sizes = {static_cast<_Size_type>(_RANGES size(_STD get<_Indices>(_Bases)))...}; + const bool _Any_zero = ((_Sizes[_Indices] == 0) || ...); + if (_Any_zero) { + return _Size_type{0}; + } + _Size_type _Product{1}; - const bool _Overflow = - (_Mul_overflow( - _Product, static_cast<_Size_type>(_RANGES size(_STD get<_Indices>(_Bases))), _Product) - || ...); + const bool _Overflow = (_Mul_overflow(_Product, _Sizes[_Indices], _Product) || ...); _STL_VERIFY(!_Overflow, "Size of cartesian product cannot be represented by size type (N4950 " "[range.cartesian.view]/10)."); return _Product; diff --git a/tests/std/tests/P2374R4_views_cartesian_product/test.cpp b/tests/std/tests/P2374R4_views_cartesian_product/test.cpp index d9e657cdeb..7a3daa44fa 100644 --- a/tests/std/tests/P2374R4_views_cartesian_product/test.cpp +++ b/tests/std/tests/P2374R4_views_cartesian_product/test.cpp @@ -973,6 +973,16 @@ namespace check_recommended_practice_implementation { // MSVC STL specific behav STATIC_ASSERT(sizeof(range_difference_t, all_t>>) > sizeof(ptrdiff_t)); } // namespace check_recommended_practice_implementation +// GH-3733: cartesian_product_view would incorrectly reject a call to size() claiming that big*big*big*0 is not +// representable as range_size_t because big*big*big is not. +constexpr void test_gh_3733() { + const auto r1 = views::repeat(0, (numeric_limits::max)()); + const auto r2 = views::repeat(1, 0); + const auto cart = views::cartesian_product(r1, r1, r1, r2); + assert(cart.size() == 0); + assert(as_const(cart).size() == 0); +} + int main() { // Check views { // ... copyable @@ -1029,4 +1039,7 @@ int main() { STATIC_ASSERT((instantiation_test(), true)); #endif // TRANSITION, GH-1030 instantiation_test(); + + STATIC_ASSERT((test_gh_3733(), true)); + test_gh_3733(); }