From de0c756746dd45c1031713f656d3a9db884a715d Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Sun, 12 Feb 2023 02:14:42 +0100 Subject: [PATCH 1/4] Implement LWG-3850 --- stl/inc/ranges | 6 ++- .../std/tests/P2278R4_views_as_const/test.cpp | 45 ++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index f163e8d799b..c1d3dcfa9ea 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -5408,7 +5408,7 @@ namespace ranges { class _As_const_fn : public _Pipe::_Base<_As_const_fn> { private: - enum class _St { _None, _All, _Reconstruct_span, _Reconstruct_ref, _Ref, _As_const }; + enum class _St { _None, _All, _Empty, _Reconstruct_span, _Reconstruct_ref, _Ref, _As_const }; template static constexpr bool _Can_reconstruct_ref_view_v = false; @@ -5423,6 +5423,8 @@ namespace ranges { if constexpr (constant_range>) { return {_St::_All, noexcept(views::all(_STD declval<_Rng>()))}; + } else if constexpr (_Is_specialization_v<_Ty, empty_view>) { + return {_St::_Empty, true}; } else if constexpr (_Is_span_v<_Ty>) { return {_St::_Reconstruct_span, true}; } else if constexpr (_Can_reconstruct_ref_view_v<_Ty>) { @@ -5448,6 +5450,8 @@ namespace ranges { if constexpr (_Strat == _St::_All) { return views::all(_STD forward<_Rng>(_Range)); + } else if constexpr (_Strat == _St::_Empty) { + return empty_view>{}; } else if constexpr (_Strat == _St::_Reconstruct_span) { return span{_STD forward<_Rng>(_Range)}; } else if constexpr (_Strat == _St::_Reconstruct_ref) { diff --git a/tests/std/tests/P2278R4_views_as_const/test.cpp b/tests/std/tests/P2278R4_views_as_const/test.cpp index 679cab731ba..498a2a8c370 100644 --- a/tests/std/tests/P2278R4_views_as_const/test.cpp +++ b/tests/std/tests/P2278R4_views_as_const/test.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include #include #include #include @@ -110,6 +111,41 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { STATIC_ASSERT(same_as); STATIC_ASSERT(noexcept(std::move(as_const(rng)) | views::as_const) == is_noexcept); } + } else if constexpr (_Is_specialization_v, ranges::empty_view>) { + // range adaptor results in empty_view reconstructed from empty_view + using ConstEmpty = ranges::empty_view>; + + { // ... with lvalue argument + STATIC_ASSERT(same_as(rng))), ConstEmpty>); + STATIC_ASSERT(noexcept(views::as_const(std::forward(rng)))); + + STATIC_ASSERT(same_as(rng) | views::as_const), ConstEmpty>); + STATIC_ASSERT(noexcept(std::forward(rng) | views::as_const)); + } + + { // ... with const lvalue argument + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(as_const(rng)))); + + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(as_const(rng) | views::as_const)); + } + + { // ... with rvalue argument + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(std::move(rng)))); + + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(std::move(rng) | views::as_const)); + } + + { // ... with const rvalue argument + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(std::move(as_const(rng))))); + + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(std::move(as_const(rng)) | views::as_const)); + } } else if constexpr (_Is_span_v) { // range adaptor results in span reconstructed from span using ConstSpan = span; @@ -179,7 +215,6 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { STATIC_ASSERT(same_as); STATIC_ASSERT(noexcept(std::move(std::as_const(rng)) | views::as_const)); } - } else if constexpr (is_lvalue_reference_v && constant_range> && !is_view) { // range adaptor results in ref_view using ConstRefView = ranges::ref_view>; @@ -545,6 +580,14 @@ int main() { test_one(views::single(333), one_int); } + { // Validate empty_view + array empty_arr; + STATIC_ASSERT(test_one(views::empty, empty_arr)); + test_one(views::empty, empty_arr); + STATIC_ASSERT(test_one(as_const(views::empty), empty_arr)); + test_one(as_const(views::empty), empty_arr); + } + #ifndef __clang__ // TRANSITION, LLVM-44833 { // empty range using Span = span; From b7e3e7da0cbd6608cb9304231157db9ebc70471a Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Sat, 11 Feb 2023 17:50:54 -0800 Subject: [PATCH 2/4] Remove extraneous `std::`-qualifications --- .../std/tests/P2278R4_views_as_const/test.cpp | 158 +++++++++--------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/tests/std/tests/P2278R4_views_as_const/test.cpp b/tests/std/tests/P2278R4_views_as_const/test.cpp index 498a2a8c370..81eed9ecb27 100644 --- a/tests/std/tests/P2278R4_views_as_const/test.cpp +++ b/tests/std/tests/P2278R4_views_as_const/test.cpp @@ -67,11 +67,11 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { if constexpr (CanViewAsConst) { constexpr bool is_noexcept = !is_view || is_nothrow_copy_constructible_v; - STATIC_ASSERT(same_as(rng))), V>); - STATIC_ASSERT(noexcept(views::as_const(std::forward(rng))) == is_noexcept); + STATIC_ASSERT(same_as(rng))), V>); + STATIC_ASSERT(noexcept(views::as_const(forward(rng))) == is_noexcept); - STATIC_ASSERT(same_as(rng) | views::as_const), V>); - STATIC_ASSERT(noexcept(std::forward(rng) | views::as_const) == is_noexcept); + STATIC_ASSERT(same_as(rng) | views::as_const), V>); + STATIC_ASSERT(noexcept(forward(rng) | views::as_const) == is_noexcept); } // ... with const lvalue argument @@ -93,11 +93,11 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { using VS = views::all_t>; constexpr bool is_noexcept = is_nothrow_move_constructible_v; - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(views::as_const(std::move(rng))) == is_noexcept); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(move(rng))) == is_noexcept); - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(std::move(rng) | views::as_const) == is_noexcept); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(move(rng) | views::as_const) == is_noexcept); } // ... with const rvalue argument @@ -105,22 +105,22 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { if constexpr (CanViewAsConst>) { constexpr bool is_noexcept = is_nothrow_copy_constructible_v; - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(views::as_const(std::move(as_const(rng)))) == is_noexcept); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(move(as_const(rng)))) == is_noexcept); - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(std::move(as_const(rng)) | views::as_const) == is_noexcept); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(move(as_const(rng)) | views::as_const) == is_noexcept); } } else if constexpr (_Is_specialization_v, ranges::empty_view>) { // range adaptor results in empty_view reconstructed from empty_view using ConstEmpty = ranges::empty_view>; { // ... with lvalue argument - STATIC_ASSERT(same_as(rng))), ConstEmpty>); - STATIC_ASSERT(noexcept(views::as_const(std::forward(rng)))); + STATIC_ASSERT(same_as(rng))), ConstEmpty>); + STATIC_ASSERT(noexcept(views::as_const(forward(rng)))); - STATIC_ASSERT(same_as(rng) | views::as_const), ConstEmpty>); - STATIC_ASSERT(noexcept(std::forward(rng) | views::as_const)); + STATIC_ASSERT(same_as(rng) | views::as_const), ConstEmpty>); + STATIC_ASSERT(noexcept(forward(rng) | views::as_const)); } { // ... with const lvalue argument @@ -132,88 +132,88 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { } { // ... with rvalue argument - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(views::as_const(std::move(rng)))); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(move(rng)))); - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(std::move(rng) | views::as_const)); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(move(rng) | views::as_const)); } { // ... with const rvalue argument - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(views::as_const(std::move(as_const(rng))))); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(move(as_const(rng))))); - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(std::move(as_const(rng)) | views::as_const)); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(move(as_const(rng)) | views::as_const)); } } else if constexpr (_Is_span_v) { // range adaptor results in span reconstructed from span using ConstSpan = span; { // ... with lvalue argument - STATIC_ASSERT(same_as(rng))), ConstSpan>); - STATIC_ASSERT(noexcept(views::as_const(std::forward(rng)))); + STATIC_ASSERT(same_as(rng))), ConstSpan>); + STATIC_ASSERT(noexcept(views::as_const(forward(rng)))); - STATIC_ASSERT(same_as(rng) | views::as_const), ConstSpan>); - STATIC_ASSERT(noexcept(std::forward(rng) | views::as_const)); + STATIC_ASSERT(same_as(rng) | views::as_const), ConstSpan>); + STATIC_ASSERT(noexcept(forward(rng) | views::as_const)); } { // ... with const lvalue argument - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(views::as_const(std::as_const(rng)))); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(as_const(rng)))); - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(std::as_const(rng) | views::as_const)); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(as_const(rng) | views::as_const)); } { // ... with rvalue argument - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(views::as_const(std::move(rng)))); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(move(rng)))); - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(std::move(rng) | views::as_const)); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(move(rng) | views::as_const)); } { // ... with const rvalue argument - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(views::as_const(std::move(std::as_const(rng))))); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(move(as_const(rng))))); - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(std::move(std::as_const(rng)) | views::as_const)); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(move(as_const(rng)) | views::as_const)); } } else if constexpr (CanReconstructRefView) { // range adaptor results in ref_view reconstructed from ref_view using ReconstructedRefView = ref_view::type>; { // ... with lvalue argument - STATIC_ASSERT(same_as(rng))), ReconstructedRefView>); - STATIC_ASSERT(noexcept(views::as_const(std::forward(rng)))); + STATIC_ASSERT(same_as(rng))), ReconstructedRefView>); + STATIC_ASSERT(noexcept(views::as_const(forward(rng)))); - STATIC_ASSERT(same_as(rng) | views::as_const), ReconstructedRefView>); - STATIC_ASSERT(noexcept(std::forward(rng) | views::as_const)); + STATIC_ASSERT(same_as(rng) | views::as_const), ReconstructedRefView>); + STATIC_ASSERT(noexcept(forward(rng) | views::as_const)); } { // ... with const lvalue argument - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(views::as_const(std::as_const(rng)))); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(as_const(rng)))); - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(std::as_const(rng) | views::as_const)); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(as_const(rng) | views::as_const)); } { //... with rvalue argument - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(views::as_const(std::move(rng)))); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(move(rng)))); - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(std::move(rng) | views::as_const)); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(move(rng) | views::as_const)); } { // ... with const rvalue argument - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(views::as_const(std::move(std::as_const(rng))))); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(move(as_const(rng))))); - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(std::move(std::as_const(rng)) | views::as_const)); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(move(as_const(rng)) | views::as_const)); } } else if constexpr (is_lvalue_reference_v && constant_range> && !is_view) { // range adaptor results in ref_view @@ -222,11 +222,11 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { // ... with lvalue argument STATIC_ASSERT(CanViewAsConst == copy_constructible); if constexpr (CanViewAsConst) { - STATIC_ASSERT(same_as(rng))), ConstRefView>); - STATIC_ASSERT(noexcept(views::as_const(std::forward(rng)))); + STATIC_ASSERT(same_as(rng))), ConstRefView>); + STATIC_ASSERT(noexcept(views::as_const(forward(rng)))); - STATIC_ASSERT(same_as(rng) | views::as_const), ConstRefView>); - STATIC_ASSERT(noexcept(std::forward(rng) | views::as_const)); + STATIC_ASSERT(same_as(rng) | views::as_const), ConstRefView>); + STATIC_ASSERT(noexcept(forward(rng) | views::as_const)); } // ... with const lvalue argument @@ -244,11 +244,11 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { if constexpr (CanViewAsConst) { constexpr bool is_noexcept = !is_view || is_nothrow_copy_constructible_v; - STATIC_ASSERT(same_as(rng))), R>); - STATIC_ASSERT(noexcept(views::as_const(std::forward(rng))) == is_noexcept); + STATIC_ASSERT(same_as(rng))), R>); + STATIC_ASSERT(noexcept(views::as_const(forward(rng))) == is_noexcept); - STATIC_ASSERT(same_as(rng) | views::as_const), R>); - STATIC_ASSERT(noexcept(std::forward(rng) | views::as_const) == is_noexcept); + STATIC_ASSERT(same_as(rng) | views::as_const), R>); + STATIC_ASSERT(noexcept(forward(rng) | views::as_const) == is_noexcept); } // ... with const lvalue argument @@ -258,11 +258,11 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { using RC = as_const_view&>>; constexpr bool is_noexcept = !is_view || is_nothrow_copy_constructible_v; - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(views::as_const(std::as_const(rng))) == is_noexcept); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(as_const(rng))) == is_noexcept); - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(std::as_const(rng) | views::as_const) == is_noexcept); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(as_const(rng) | views::as_const) == is_noexcept); } // ... with rvalue argument @@ -271,11 +271,11 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { using RS = as_const_view>>; constexpr bool is_noexcept = is_nothrow_move_constructible_v; - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(views::as_const(std::move(rng))) == is_noexcept); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(move(rng))) == is_noexcept); - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(std::move(rng) | views::as_const) == is_noexcept); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(move(rng) | views::as_const) == is_noexcept); } // ... with const rvalue argument @@ -283,16 +283,16 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { if constexpr (CanViewAsConst>) { constexpr bool is_noexcept = is_nothrow_copy_constructible_v; - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(views::as_const(std::move(std::as_const(rng)))) == is_noexcept); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::as_const(move(as_const(rng)))) == is_noexcept); - STATIC_ASSERT(same_as); - STATIC_ASSERT(noexcept(std::move(std::as_const(rng)) | views::as_const) == is_noexcept); + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(move(as_const(rng)) | views::as_const) == is_noexcept); } } // Validate deduction guide - same_as auto r = as_const_view{std::forward(rng)}; + same_as auto r = as_const_view{forward(rng)}; // Validate as_const_view::size STATIC_ASSERT(CanMemberSize == sized_range); @@ -472,8 +472,8 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { } // Validate as_const_view::base() && - same_as auto b2 = std::move(r).base(); - STATIC_ASSERT(noexcept(std::move(r).base()) == is_nothrow_move_constructible_v); + same_as auto b2 = move(r).base(); + STATIC_ASSERT(noexcept(move(r).base()) == is_nothrow_move_constructible_v); if (!is_empty) { assert(*b2.begin() == *begin(expected)); } From db106219555e8e19775cd5eb5926f1b698848a5d Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Sat, 11 Feb 2023 17:51:39 -0800 Subject: [PATCH 3/4] Supress "dereferencing NULL pointer" static analysis wanrings --- tests/std/tests/P2278R4_views_as_const/test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/std/tests/P2278R4_views_as_const/test.cpp b/tests/std/tests/P2278R4_views_as_const/test.cpp index 81eed9ecb27..de30f25718e 100644 --- a/tests/std/tests/P2278R4_views_as_const/test.cpp +++ b/tests/std/tests/P2278R4_views_as_const/test.cpp @@ -338,6 +338,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { { const same_as> auto i = r.begin(); if (!is_empty) { +#pragma warning(suppress : 6011) // Dereferencing NULL pointer 'i' assert(*i == *begin(expected)); } @@ -345,6 +346,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { auto r2 = r; const same_as> auto i2 = r2.begin(); if (!is_empty) { +#pragma warning(suppress : 6011) // Dereferencing NULL pointer 'i' assert(*i2 == *i); } } @@ -355,6 +357,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { if constexpr (CanMemberBegin) { const same_as> auto ci = as_const(r).begin(); if (!is_empty) { +#pragma warning(suppress : 6011) // Dereferencing NULL pointer 'i' assert(*ci == *begin(expected)); } @@ -362,6 +365,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { const auto cr2 = r; const same_as> auto ci2 = cr2.begin(); if (!is_empty) { +#pragma warning(suppress : 6011) // Dereferencing NULL pointer 'i' assert(*ci2 == *ci); } } From db6b039f94872ddacaac92d7795ed3316a2b6e37 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Sat, 11 Feb 2023 23:34:59 -0800 Subject: [PATCH 4/4] Properly handle empty_view --- stl/inc/ranges | 2 +- .../std/tests/P2278R4_views_as_const/test.cpp | 35 ++++++++++++++----- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index c1d3dcfa9ea..ca5335d40e7 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -5451,7 +5451,7 @@ namespace ranges { if constexpr (_Strat == _St::_All) { return views::all(_STD forward<_Rng>(_Range)); } else if constexpr (_Strat == _St::_Empty) { - return empty_view>{}; + return empty_view>>{}; } else if constexpr (_Strat == _St::_Reconstruct_span) { return span{_STD forward<_Rng>(_Range)}; } else if constexpr (_Strat == _St::_Reconstruct_ref) { diff --git a/tests/std/tests/P2278R4_views_as_const/test.cpp b/tests/std/tests/P2278R4_views_as_const/test.cpp index de30f25718e..d44b0890b0c 100644 --- a/tests/std/tests/P2278R4_views_as_const/test.cpp +++ b/tests/std/tests/P2278R4_views_as_const/test.cpp @@ -38,6 +38,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { using ranges::ref_view, ranges::as_const_view, ranges::begin, ranges::end, ranges::iterator_t, ranges::sentinel_t, ranges::prev, ranges::forward_range, ranges::bidirectional_range, ranges::random_access_range, ranges::contiguous_range, ranges::common_range, ranges::sized_range, ranges::constant_range; + using V = views::all_t; using R = as_const_view; @@ -48,7 +49,8 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { STATIC_ASSERT(forward_range == forward_range); STATIC_ASSERT(bidirectional_range == bidirectional_range); STATIC_ASSERT(random_access_range == random_access_range); - STATIC_ASSERT(contiguous_range == contiguous_range); + STATIC_ASSERT(contiguous_range + == (contiguous_range && is_lvalue_reference_v>>) ); STATIC_ASSERT(constant_range); STATIC_ASSERT(!indirectly_writable, ranges::range_value_t>); @@ -113,7 +115,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { } } else if constexpr (_Is_specialization_v, ranges::empty_view>) { // range adaptor results in empty_view reconstructed from empty_view - using ConstEmpty = ranges::empty_view>; + using ConstEmpty = ranges::empty_view>>; { // ... with lvalue argument STATIC_ASSERT(same_as(rng))), ConstEmpty>); @@ -338,6 +340,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { { const same_as> auto i = r.begin(); if (!is_empty) { + // (static analyzer doesn't realize that `i == nullptr` implies `is_empty`) #pragma warning(suppress : 6011) // Dereferencing NULL pointer 'i' assert(*i == *begin(expected)); } @@ -412,17 +415,17 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { } // Validate view_interface::data - STATIC_ASSERT(CanMemberData == contiguous_range); - STATIC_ASSERT(CanData == contiguous_range); - if constexpr (contiguous_range) { + STATIC_ASSERT(CanMemberData == contiguous_range); + STATIC_ASSERT(CanData == contiguous_range); + if constexpr (contiguous_range) { const same_as>*> auto ptr = r.data(); assert(ptr == to_address(r.begin())); } // Validate view_interface::data (const) - STATIC_ASSERT(CanMemberData == contiguous_range); - STATIC_ASSERT(CanData == contiguous_range); - if constexpr (contiguous_range) { + STATIC_ASSERT(CanMemberData == contiguous_range); + STATIC_ASSERT(CanData == contiguous_range); + if constexpr (contiguous_range) { const same_as>*> auto ptr = as_const(r).data(); assert(ptr == to_address(as_const(r).begin())); } @@ -586,10 +589,26 @@ int main() { { // Validate empty_view array empty_arr; + STATIC_ASSERT(test_one(views::empty, empty_arr)); test_one(views::empty, empty_arr); STATIC_ASSERT(test_one(as_const(views::empty), empty_arr)); test_one(as_const(views::empty), empty_arr); + + STATIC_ASSERT(test_one(views::empty, empty_arr)); + test_one(views::empty, empty_arr); + STATIC_ASSERT(test_one(as_const(views::empty), empty_arr)); + test_one(as_const(views::empty), empty_arr); + + STATIC_ASSERT(test_one(views::empty, empty_arr)); + test_one(views::empty, empty_arr); + STATIC_ASSERT(test_one(as_const(views::empty), empty_arr)); + test_one(as_const(views::empty), empty_arr); + + STATIC_ASSERT(test_one(views::empty, empty_arr)); + test_one(views::empty, empty_arr); + STATIC_ASSERT(test_one(as_const(views::empty), empty_arr)); + test_one(as_const(views::empty), empty_arr); } #ifndef __clang__ // TRANSITION, LLVM-44833