From e8ed216dd6081b59ea767318409e2f7ed99b1a50 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Mon, 14 Nov 2022 17:28:29 -0800 Subject: [PATCH 1/3] P2602R2 Poison Pills Are Too Toxic Consistently annotate throughout with `// intentional ADL` and `// Block unqualified name lookup`. Drive-by: * Consistently use east `const` in `P0896R4_ranges_machinery`. * Feeature-test macro test fixes: * `__cpp_lib_concepts` should not be defined in sub-C++20-modes * `__cpp_lib_ranges` should not be defined in sub-C++20 modes even if `__cpp_lib_concepts` is defined. (This is redundant with the previous fix, but it doesn't hurt anything.) Fixes #3209 --- stl/inc/compare | 48 ++++++------ stl/inc/concepts | 4 +- stl/inc/xutility | 74 ++++++++---------- stl/inc/yvals_core.h | 3 +- tests/libcxx/expected_results.txt | 7 ++ tests/libcxx/skipped_tests.txt | 7 ++ .../P0896R4_ranges_range_machinery/test.cpp | 78 ++++++++++--------- .../test.compile.pass.cpp | 10 +-- 8 files changed, 118 insertions(+), 113 deletions(-) diff --git a/stl/inc/compare b/stl/inc/compare index 9d605211d8..7fd027577f 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -363,8 +363,9 @@ namespace _Strong_order { void strong_order(); // Block unqualified name lookup; see GH-1374. template - concept _Has_ADL = - requires(_Ty1& _Left, _Ty2& _Right) { static_cast(/* ADL */ strong_order(_Left, _Right)); }; + concept _Has_ADL = requires(_Ty1& _Left, _Ty2& _Right) { + static_cast(strong_order(_Left, _Right)); // intentional ADL + }; template concept _Can_compare_three_way = @@ -380,7 +381,7 @@ namespace _Strong_order { return {_St::_None}; } else if constexpr (_Has_ADL<_Ty1, _Ty2>) { return {_St::_Adl, noexcept(static_cast( - /* ADL */ strong_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))}; + strong_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))}; // intentional ADL } else if constexpr (floating_point>) { return {_St::_Floating, true}; } else if constexpr (_Can_compare_three_way<_Ty1, _Ty2>) { @@ -401,7 +402,7 @@ namespace _Strong_order { noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) { constexpr _St _Strat = _Choice<_Ty1&, _Ty2&>._Strategy; if constexpr (_Strat == _St::_Adl) { - return static_cast(/* ADL */ strong_order(_Left, _Right)); + return static_cast(strong_order(_Left, _Right)); // intentional ADL } else if constexpr (_Strat == _St::_Floating) { using _Floating_type = decay_t<_Ty1>; using _Traits = _Floating_type_traits<_Floating_type>; @@ -454,8 +455,9 @@ namespace _Weak_order { void weak_order(); // Block unqualified name lookup; see GH-1374. template - concept _Has_ADL = - requires(_Ty1& _Left, _Ty2& _Right) { static_cast(/* ADL */ weak_order(_Left, _Right)); }; + concept _Has_ADL = requires(_Ty1& _Left, _Ty2& _Right) { + static_cast(weak_order(_Left, _Right)); // intentional ADL + }; template concept _Can_compare_three_way = @@ -474,16 +476,15 @@ namespace _Weak_order { return {_St::_None}; } else if constexpr (_Has_ADL<_Ty1, _Ty2>) { return {_St::_Adl, noexcept(static_cast( - /* ADL */ weak_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))}; + weak_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))}; // intentional ADL } else if constexpr (floating_point>) { return {_St::_Floating, true}; } else if constexpr (_Can_compare_three_way<_Ty1, _Ty2>) { return {_St::_Three, noexcept(static_cast( compare_three_way{}(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))}; } else if constexpr (_Strong_order::_Has_ADL<_Ty1, _Ty2>) { - return {_St::_Strong, noexcept(static_cast(static_cast( - /* ADL, throughput optimization */ strong_order( - _STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))}; + return {_St::_Strong, noexcept(static_cast(static_cast(strong_order( + _STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))}; // intentional ADL } else { return {_St::_None}; } @@ -499,7 +500,7 @@ namespace _Weak_order { noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) { constexpr _St _Strat = _Choice<_Ty1&, _Ty2&>._Strategy; if constexpr (_Strat == _St::_Adl) { - return static_cast(/* ADL */ weak_order(_Left, _Right)); + return static_cast(weak_order(_Left, _Right)); // intentional ADL } else if constexpr (_Strat == _St::_Floating) { using _Floating_type = decay_t<_Ty1>; using _Traits = _Floating_type_traits<_Floating_type>; @@ -554,7 +555,7 @@ namespace _Weak_order { return static_cast(compare_three_way{}(_Left, _Right)); } else if constexpr (_Strat == _St::_Strong) { return static_cast( - static_cast(/* ADL, throughput optimization */ strong_order(_Left, _Right))); + static_cast(strong_order(_Left, _Right))); // intentional ADL } else { static_assert(_Always_false<_Ty1>, "should be unreachable"); } @@ -570,8 +571,9 @@ namespace _Partial_order { void partial_order(); // Block unqualified name lookup; see GH-1374. template - concept _Has_ADL = - requires(_Ty1& _Left, _Ty2& _Right) { static_cast(/* ADL */ partial_order(_Left, _Right)); }; + concept _Has_ADL = requires(_Ty1& _Left, _Ty2& _Right) { + static_cast(partial_order(_Left, _Right)); // intentional ADL + }; template concept _Can_compare_three_way = @@ -591,19 +593,17 @@ namespace _Partial_order { if constexpr (!same_as, decay_t<_Ty2>>) { return {_St::_None}; } else if constexpr (_Has_ADL<_Ty1, _Ty2>) { - return {_St::_Adl, noexcept(static_cast( - /* ADL */ partial_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))}; + return {_St::_Adl, noexcept(static_cast(partial_order( + _STD declval<_Ty1&>(), _STD declval<_Ty2&>())))}; // intentional ADL } else if constexpr (_Can_compare_three_way<_Ty1, _Ty2>) { return {_St::_Three, noexcept(static_cast( compare_three_way{}(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))}; } else if constexpr (_Weak_order::_Has_ADL<_Ty1, _Ty2>) { - return {_St::_Weak, - noexcept(static_cast(static_cast( - /* ADL, throughput optimization */ weak_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))}; + return {_St::_Weak, noexcept(static_cast(static_cast( + weak_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))}; // intentional ADL } else if constexpr (_Strong_order::_Has_ADL<_Ty1, _Ty2>) { - return {_St::_Strong, noexcept(static_cast(static_cast( - /* ADL, throughput optimization */ strong_order( - _STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))}; + return {_St::_Strong, noexcept(static_cast(static_cast(strong_order( + _STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))}; // intentional ADL } else { return {_St::_None}; } @@ -624,10 +624,10 @@ namespace _Partial_order { return static_cast(compare_three_way{}(_Left, _Right)); } else if constexpr (_Strat == _St::_Weak) { return static_cast( - static_cast(/* ADL, throughput optimization */ weak_order(_Left, _Right))); + static_cast(weak_order(_Left, _Right))); // intentional ADL } else if constexpr (_Strat == _St::_Strong) { return static_cast( - static_cast(/* ADL, throughput optimization */ strong_order(_Left, _Right))); + static_cast(strong_order(_Left, _Right))); // intentional ADL } else { static_assert(_Always_false<_Ty1>, "should be unreachable"); } diff --git a/stl/inc/concepts b/stl/inc/concepts index 49585e00ea..6ca7e60424 100644 --- a/stl/inc/concepts +++ b/stl/inc/concepts @@ -127,7 +127,7 @@ namespace ranges { template concept _Use_ADL_swap = (_Has_class_or_enum_type<_Ty1> || _Has_class_or_enum_type<_Ty2>) && requires(_Ty1&& __t, _Ty2&& __u) { - swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)); + swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)); // intentional ADL }; struct _Cpo { @@ -135,7 +135,7 @@ namespace ranges { requires _Use_ADL_swap<_Ty1, _Ty2> constexpr void operator()(_Ty1&& __t, _Ty2&& __u) const noexcept(noexcept(swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)))) { - swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)); + swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)); // intentional ADL } template diff --git a/stl/inc/xutility b/stl/inc/xutility index cb697f0e4c..571c841fce 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -407,7 +407,7 @@ namespace ranges { // clang-format off template concept _Has_ADL = _Has_class_or_enum_type<_Ty> && requires(_Ty&& __t) { - iter_move(static_cast<_Ty&&>(__t)); + iter_move(static_cast<_Ty&&>(__t)); // intentional ADL }; template @@ -423,7 +423,7 @@ namespace ranges { template _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { if constexpr (_Has_ADL<_Ty>) { - return {_St::_Custom, noexcept(iter_move(_STD declval<_Ty>()))}; + return {_St::_Custom, noexcept(iter_move(_STD declval<_Ty>()))}; // intentional ADL } else if constexpr (_Can_deref<_Ty>) { return {_St::_Fallback, noexcept(*_STD declval<_Ty>())}; } else { @@ -441,7 +441,7 @@ namespace ranges { constexpr _St _Strat = _Choice<_Ty>._Strategy; if constexpr (_Strat == _St::_Custom) { - return iter_move(static_cast<_Ty&&>(_Val)); + return iter_move(static_cast<_Ty&&>(_Val)); // intentional ADL } else if constexpr (_Strat == _St::_Fallback) { using _Ref = decltype(*static_cast<_Ty&&>(_Val)); if constexpr (is_lvalue_reference_v<_Ref>) { @@ -723,7 +723,7 @@ namespace ranges { template concept _Has_ADL = (_Has_class_or_enum_type<_Ty1> || _Has_class_or_enum_type<_Ty2>) && requires(_Ty1&& __t1, _Ty2&& __t2) { - iter_swap(static_cast<_Ty1&&>(__t1), static_cast<_Ty2&&>(__t2)); + iter_swap(static_cast<_Ty1&&>(__t1), static_cast<_Ty2&&>(__t2)); // intentional ADL }; template @@ -752,12 +752,13 @@ namespace ranges { template _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { if constexpr (_Has_ADL<_Ty1, _Ty2>) { - return {_St::_Custom, noexcept(iter_swap(_STD declval<_Ty1>(), _STD declval<_Ty2>()))}; + return {_St::_Custom, + noexcept(iter_swap(_STD declval<_Ty1>(), _STD declval<_Ty2>()))}; // intentional ADL } else if constexpr (_Can_swap_references<_Ty1, _Ty2>) { return {_St::_Swap, noexcept(_RANGES swap(*_STD declval<_Ty1>(), *_STD declval<_Ty2>()))}; } else if constexpr (_Symmetric_indirectly_movable_storable<_Ty1, _Ty2>) { - constexpr auto _Nothrow = noexcept( - *_STD declval<_Ty1>() = _Iter_exchange_move(_STD declval<_Ty2>(), _STD declval<_Ty1>())); + constexpr auto _Nothrow = noexcept(*_STD declval<_Ty1>() = _Iter_swap::_Iter_exchange_move( + _STD declval<_Ty2>(), _STD declval<_Ty1>())); return {_St::_Exchange, _Nothrow}; } else { return {_St::_None}; @@ -774,12 +775,12 @@ namespace ranges { constexpr _St _Strat = _Choice<_Ty1, _Ty2>._Strategy; if constexpr (_Strat == _St::_Custom) { - (void) iter_swap(static_cast<_Ty1&&>(_Val1), static_cast<_Ty2&&>(_Val2)); + (void) iter_swap(static_cast<_Ty1&&>(_Val1), static_cast<_Ty2&&>(_Val2)); // intentional ADL } else if constexpr (_Strat == _St::_Swap) { _RANGES swap(*static_cast<_Ty1&&>(_Val1), *static_cast<_Ty2&&>(_Val2)); } else if constexpr (_Strat == _St::_Exchange) { *static_cast<_Ty1&&>(_Val1) = - _Iter_exchange_move(static_cast<_Ty2&&>(_Val2), static_cast<_Ty1&&>(_Val1)); + _Iter_swap::_Iter_exchange_move(static_cast<_Ty2&&>(_Val2), static_cast<_Ty1&&>(_Val1)); } else { static_assert(_Always_false<_Ty1>, "should be unreachable"); } @@ -2088,10 +2089,7 @@ namespace ranges { concept _Should_range_access = is_lvalue_reference_v<_Rng> || enable_borrowed_range>; namespace _Begin { - template - void begin(_Ty&) = delete; - template - void begin(const _Ty&) = delete; + void begin(); // Block unqualified name lookup template concept _Has_member = requires(_Ty __t) { @@ -2101,7 +2099,7 @@ namespace ranges { template concept _Has_ADL = _Has_class_or_enum_type<_Ty> // && requires(_Ty __t) { - { _Fake_copy_init(begin(__t)) } -> input_or_output_iterator; + { _Fake_copy_init(begin(__t)) } -> input_or_output_iterator; // intentional ADL }; class _Cpo { @@ -2120,7 +2118,7 @@ namespace ranges { } else if constexpr (_Has_member<_Ty>) { return {_St::_Member, noexcept(_Fake_copy_init(_STD declval<_Ty>().begin()))}; } else if constexpr (_Has_ADL<_Ty>) { - return {_St::_Non_member, noexcept(_Fake_copy_init(begin(_STD declval<_Ty>())))}; + return {_St::_Non_member, noexcept(_Fake_copy_init(begin(_STD declval<_Ty>())))}; // intentional ADL } else { return {_St::_None}; } @@ -2140,7 +2138,7 @@ namespace ranges { } else if constexpr (_Strat == _St::_Member) { return _Val.begin(); } else if constexpr (_Strat == _St::_Non_member) { - return begin(_Val); + return begin(_Val); // intentional ADL } else { static_assert(_Always_false<_Ty>, "Should be unreachable"); } @@ -2156,10 +2154,7 @@ namespace ranges { using iterator_t = decltype(_RANGES begin(_STD declval<_Ty&>())); namespace _End { - template - void end(_Ty&) = delete; - template - void end(const _Ty&) = delete; + void end(); // Block unqualified name lookup template concept _Has_member = requires(_Ty __t) { @@ -2169,7 +2164,7 @@ namespace ranges { template concept _Has_ADL = _Has_class_or_enum_type<_Ty> // && requires(_Ty __t) { - { _Fake_copy_init(end(__t)) } -> sentinel_for>; + { _Fake_copy_init(end(__t)) } -> sentinel_for>; // intentional ADL }; class _Cpo { @@ -2194,7 +2189,7 @@ namespace ranges { } else if constexpr (_Has_member<_Ty>) { return {_St::_Member, noexcept(_Fake_copy_init(_STD declval<_Ty>().end()))}; } else if constexpr (_Has_ADL<_Ty>) { - return {_St::_Non_member, noexcept(_Fake_copy_init(end(_STD declval<_Ty>())))}; + return {_St::_Non_member, noexcept(_Fake_copy_init(end(_STD declval<_Ty>())))}; // intentional ADL } else { return {_St::_None}; } @@ -2215,7 +2210,7 @@ namespace ranges { } else if constexpr (_Strat == _St::_Member) { return _Val.end(); } else if constexpr (_Strat == _St::_Non_member) { - return end(_Val); + return end(_Val); // intentional ADL } else { static_assert(_Always_false<_Ty>, "should be unreachable"); } @@ -2499,10 +2494,7 @@ namespace ranges { } namespace _Rbegin { - template - void rbegin(_Ty&) = delete; - template - void rbegin(const _Ty&) = delete; + void rbegin(); // Block unqualified name lookup template concept _Has_member = requires(_Ty __t) { @@ -2512,7 +2504,7 @@ namespace ranges { template concept _Has_ADL = _Has_class_or_enum_type<_Ty> // && requires(_Ty __t) { - { _Fake_copy_init(rbegin(__t)) } -> input_or_output_iterator; + { _Fake_copy_init(rbegin(__t)) } -> input_or_output_iterator; // intentional ADL }; template @@ -2531,7 +2523,8 @@ namespace ranges { if constexpr (_Has_member<_Ty>) { return {_St::_Member, noexcept(_Fake_copy_init(_STD declval<_Ty>().rbegin()))}; } else if constexpr (_Has_ADL<_Ty>) { - return {_St::_Non_member, noexcept(_Fake_copy_init(rbegin(_STD declval<_Ty>())))}; + return { + _St::_Non_member, noexcept(_Fake_copy_init(rbegin(_STD declval<_Ty>())))}; // intentional ADL } else if constexpr (_Can_make_reverse<_Ty>) { return {_St::_Make_reverse, noexcept(_STD make_reverse_iterator(_RANGES end(_STD declval<_Ty>())))}; } else { @@ -2551,7 +2544,7 @@ namespace ranges { if constexpr (_Strat == _St::_Member) { return _Val.rbegin(); } else if constexpr (_Strat == _St::_Non_member) { - return rbegin(_Val); + return rbegin(_Val); // intentional ADL } else if constexpr (_Strat == _St::_Make_reverse) { return _STD make_reverse_iterator(_RANGES end(_Val)); } else { @@ -2566,10 +2559,7 @@ namespace ranges { } namespace _Rend { - template - void rend(_Ty&) = delete; - template - void rend(const _Ty&) = delete; + void rend(); // Block unqualified name lookup template concept _Has_member = requires(_Ty __t) { @@ -2579,6 +2569,7 @@ namespace ranges { template concept _Has_ADL = _Has_class_or_enum_type<_Ty> // && requires(_Ty __t) { + // intentional ADL { _Fake_copy_init(rend(__t)) } -> sentinel_for; }; @@ -2598,7 +2589,7 @@ namespace ranges { if constexpr (_Has_member<_Ty>) { return {_St::_Member, noexcept(_Fake_copy_init(_STD declval<_Ty>().rend()))}; } else if constexpr (_Has_ADL<_Ty>) { - return {_St::_Non_member, noexcept(_Fake_copy_init(rend(_STD declval<_Ty>())))}; + return {_St::_Non_member, noexcept(_Fake_copy_init(rend(_STD declval<_Ty>())))}; // intentional ADL } else if constexpr (_Can_make_reverse<_Ty>) { return { _St::_Make_reverse, noexcept(_STD make_reverse_iterator(_RANGES begin(_STD declval<_Ty>())))}; @@ -2619,7 +2610,7 @@ namespace ranges { if constexpr (_Strat == _St::_Member) { return _Val.rend(); } else if constexpr (_Strat == _St::_Non_member) { - return rend(_Val); + return rend(_Val); // intentional ADL } else if constexpr (_Strat == _St::_Make_reverse) { return _STD make_reverse_iterator(_RANGES begin(_Val)); } else { @@ -2687,10 +2678,7 @@ namespace ranges { inline constexpr bool disable_sized_range = false; namespace _Size { - template - void size(_Ty&) = delete; - template - void size(const _Ty&) = delete; + void size(); // Block unqualified name lookup template concept _Has_member = (!disable_sized_range<_UnCV>) // @@ -2701,7 +2689,7 @@ namespace ranges { template concept _Has_ADL = _Has_class_or_enum_type<_Ty> && (!disable_sized_range<_UnCV>) // && requires(_Ty __t) { - { _Fake_copy_init(size(__t)) } -> _Integer_like; + { _Fake_copy_init(size(__t)) } -> _Integer_like; // intentional ADL }; template @@ -2728,7 +2716,7 @@ namespace ranges { } else if constexpr (_Has_member<_Ty, _UnCV>) { return {_St::_Member, noexcept(_Fake_copy_init(_STD declval<_Ty>().size()))}; } else if constexpr (_Has_ADL<_Ty, _UnCV>) { - return {_St::_Non_member, noexcept(_Fake_copy_init(size(_STD declval<_Ty>())))}; + return {_St::_Non_member, noexcept(_Fake_copy_init(size(_STD declval<_Ty>())))}; // intentional ADL } else if constexpr (_Can_difference<_Ty>) { return {_St::_Subtract, noexcept(_RANGES end(_STD declval<_Ty>()) - _RANGES begin(_STD declval<_Ty>()))}; @@ -2752,7 +2740,7 @@ namespace ranges { } else if constexpr (_Strat == _St::_Member) { return _Val.size(); } else if constexpr (_Strat == _St::_Non_member) { - return size(_Val); + return size(_Val); // intentional ADL } else if constexpr (_Strat == _St::_Subtract) { const auto _Delta = _RANGES end(_Val) - _RANGES begin(_Val); return static_cast<_Make_unsigned_like_t>>(_Delta); diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index ad10a9d0e8..eed8d834d3 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -345,6 +345,7 @@ // P2494R2 Relaxing Range Adaptors To Allow Move-Only Types // P2499R0 string_view Range Constructor Should Be explicit // P2549R1 unexpected::error() +// P2602R2 Poison Pills Are Too Toxic // Parallel Algorithms Notes // C++ allows an implementation to implement parallel algorithms as calls to the serial algorithms. @@ -1734,7 +1735,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #if defined(__cpp_lib_concepts) // TRANSITION, GH-395 #if _HAS_CXX23 -#define __cpp_lib_ranges 202207L // P2494R2 Relaxing Range Adaptors To Allow Move-Only Types +#define __cpp_lib_ranges 202211L // P2602R2 Poison Pills Are Too Toxic #elif _HAS_CXX20 // ^^^ _HAS_CXX23 / _HAS_CXX20 vvv #define __cpp_lib_ranges 202110L // P2415R2 What Is A view? #endif // _HAS_CXX20 diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 95c0064f6f..a77a6c9724 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -633,6 +633,13 @@ std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp FAIL # libc++ is missing a requires-clause on variant's operator<=> (llvm/llvm-project#58192) std/utilities/variant/variant.relops/three_way.pass.cpp FAIL +# libc++ doesn't yet implement P2602R2 "Poison Pills Are Too Toxic" +std/ranges/range.access/begin.pass.cpp FAIL +std/ranges/range.access/end.pass.cpp FAIL +std/ranges/range.access/rbegin.pass.cpp FAIL +std/ranges/range.access/rend.pass.cpp FAIL +std/ranges/range.access/size.pass.cpp FAIL + # *** LIKELY STL BUGS *** # Not yet analyzed, likely STL bugs. Various assertions. diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 0567534613..fdcf3360ad 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -633,6 +633,13 @@ utilities\variant\variant.variant\variant.ctor\T.pass.cpp # libc++ is missing a requires-clause on variant's operator<=> (llvm/llvm-project#58192) utilities\variant\variant.relops\three_way.pass.cpp +# libc++ doesn't yet implement P2602R2 "Poison Pills Are Too Toxic" +ranges\range.access\begin.pass.cpp +ranges\range.access\end.pass.cpp +ranges\range.access\rbegin.pass.cpp +ranges\range.access\rend.pass.cpp +ranges\range.access\size.pass.cpp + # *** LIKELY STL BUGS *** # Not yet analyzed, likely STL bugs. Various assertions. diff --git a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp index 7076deb301..18b8c52348 100644 --- a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp @@ -34,7 +34,7 @@ STATIC_ASSERT(std::same_as, std::size_t>); // GH-2358: : path's comparison operators are IF-NDR static_assert(ranges::range); -static_assert(ranges::range); +static_assert(ranges::range); template concept Decayed = std::same_as, T>; @@ -1088,7 +1088,7 @@ STATIC_ASSERT(test_cdata const&, int*>()); #endif // C++20 using valarray_int_iterator = decltype(std::begin(std::declval&>())); -using const_valarray_int_iterator = decltype(std::begin(std::declval&>())); +using const_valarray_int_iterator = decltype(std::begin(std::declval const&>())); STATIC_ASSERT(test_begin>()); STATIC_ASSERT(test_end>()); STATIC_ASSERT(test_cbegin>()); @@ -1631,7 +1631,7 @@ struct badsized_range : Base { // size() launches the missiles. static_assert(always_false); } - [[noreturn]] friend int size(const badsized_range&) { + [[noreturn]] friend int size(badsized_range const&) { static_assert(always_false); } }; @@ -1670,9 +1670,9 @@ STATIC_ASSERT(!std::is_base_of_v or enable_view is never true STATIC_ASSERT(ranges::enable_view); STATIC_ASSERT(!ranges::enable_view); -STATIC_ASSERT(!ranges::enable_view); +STATIC_ASSERT(!ranges::enable_view); STATIC_ASSERT(!ranges::enable_view); -STATIC_ASSERT(!ranges::enable_view); +STATIC_ASSERT(!ranges::enable_view); // Verify that the derived-from-view_interface mechanism can handle uses of incomplete types whenever possible struct incomplet; @@ -1852,7 +1852,7 @@ constexpr bool complicated_algorithm_test() { // Regression test for DevCom-739010 (aka VSO-985597) // https://developercommunity.visualstudio.com/content/problem/739010/meow.html -// which allows overload resolution to prefer a hidden friend `const T&` overload of `begin` +// which allows overload resolution to prefer a hidden friend `T const&` overload of `begin` // for an rvalue `T` over the deleted `begin(T&&)` instantiated from the poison pill. template struct bad_string_view { @@ -1886,62 +1886,64 @@ STATIC_ASSERT(ranges::viewable_range>); STATIC_ASSERT(ranges::viewable_range const>); namespace poison_pill_test { + static int some_int = 42; + template - auto begin(T&) { - STATIC_ASSERT(always_false); + int* begin(T&) { + return &some_int; } template - auto begin(const T&) { - STATIC_ASSERT(always_false); + int const* begin(T const&) { + return &some_int; } template - auto end(T&) { - STATIC_ASSERT(always_false); + int* end(T&) { + return &some_int + 1; } template - auto end(const T&) { - STATIC_ASSERT(always_false); + int const* end(T const&) { + return &some_int + 1; } template auto rbegin(T&) { - STATIC_ASSERT(always_false); + return std::reverse_iterator{&some_int + 1}; } template - auto rbegin(const T&) { - STATIC_ASSERT(always_false); + auto rbegin(T const&) { + return std::reverse_iterator{&some_int + 1}; } template auto rend(T&) { - STATIC_ASSERT(always_false); + return std::reverse_iterator{&some_int}; } template - auto rend(const T&) { - STATIC_ASSERT(always_false); + auto rend(T const&) { + return std::reverse_iterator{&some_int}; } template auto size(T&) { - STATIC_ASSERT(always_false); + return std::size_t{1}; } template - auto size(const T&) { - STATIC_ASSERT(always_false); + auto size(T const&) { + return std::size_t{1}; } struct some_type {}; - // The above underconstrained templates should be blocked by the poison pills for the ranges CPOs tested below; - // that is not the case in N4849, which P2091 will fix. - - STATIC_ASSERT(!CanBegin); - STATIC_ASSERT(!CanBegin); - STATIC_ASSERT(!CanEnd); - STATIC_ASSERT(!CanEnd); - STATIC_ASSERT(!CanRBegin); - STATIC_ASSERT(!CanRBegin); - STATIC_ASSERT(!CanREnd); - STATIC_ASSERT(!CanREnd); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); + // The above underconstrained templates were blocked by the poison pills for the ranges CPOs + // until P2602R2 removed them. + + STATIC_ASSERT(CanBegin); + STATIC_ASSERT(CanBegin); + STATIC_ASSERT(CanEnd); + STATIC_ASSERT(CanEnd); + STATIC_ASSERT(CanRBegin); + STATIC_ASSERT(CanRBegin); + STATIC_ASSERT(CanREnd); + STATIC_ASSERT(CanREnd); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanSize); } // namespace poison_pill_test namespace unwrapped_begin_end { @@ -2013,13 +2015,13 @@ namespace closure { constexpr arg(arg&) { static_assert(Allowed == GLValueKind::lvalue); } - constexpr arg(const arg&) { + constexpr arg(arg const&) { static_assert(Allowed == GLValueKind::const_lvalue); } constexpr arg(arg&&) { static_assert(Allowed == GLValueKind::xvalue); } - constexpr arg(const arg&&) { + constexpr arg(arg const&&) { static_assert(Allowed == GLValueKind::const_xvalue); } diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 80265e0975..74c82778cf 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -30,7 +30,7 @@ STATIC_ASSERT(__cpp_lib_adaptor_iterator_pair_constructor == 202106L); STATIC_ASSERT(__cpp_lib_addressof_constexpr == 201603L); #endif -#ifdef __cpp_lib_concepts +#if _HAS_CXX20 && defined(__cpp_lib_concepts) #ifndef __cpp_lib_algorithm_iterator_requirements #error __cpp_lib_algorithm_iterator_requirements is not defined #elif __cpp_lib_algorithm_iterator_requirements != 202207L @@ -1499,12 +1499,12 @@ STATIC_ASSERT(__cpp_lib_quoted_string_io == 201304L); #if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 #ifndef __cpp_lib_ranges #error __cpp_lib_ranges is not defined -#elif __cpp_lib_ranges != 202207L -#error __cpp_lib_ranges is not 202207L +#elif __cpp_lib_ranges != 202211L +#error __cpp_lib_ranges is not 202211L #else -STATIC_ASSERT(__cpp_lib_ranges == 202207L); +STATIC_ASSERT(__cpp_lib_ranges == 202211L); #endif -#elif defined(__cpp_lib_concepts) +#elif _HAS_CXX20 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 #ifndef __cpp_lib_ranges #error __cpp_lib_ranges is not defined #elif __cpp_lib_ranges != 202110L From ceb62d3ed522c0e6485ef1dfab75c5ae44aee8eb Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 18 Nov 2022 13:33:57 -0800 Subject: [PATCH 2/3] Review comments --- stl/inc/compare | 39 ++++++++++++++--- stl/inc/concepts | 2 +- stl/inc/type_traits | 6 ++- stl/inc/xutility | 36 +++++++++++++--- .../P0896R4_ranges_range_machinery/test.cpp | 42 +++++-------------- .../test.compile.pass.cpp | 2 +- 6 files changed, 80 insertions(+), 47 deletions(-) diff --git a/stl/inc/compare b/stl/inc/compare index 7fd027577f..c107c658d7 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -360,7 +360,11 @@ using _Synth_three_way_result = decltype(_Synth_three_way{}(_STD declval<_Ty1&>( // Note: The following CPOs are passing arguments as lvalues; see GH-1374. namespace _Strong_order { - void strong_order(); // Block unqualified name lookup; see GH-1374. +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void strong_order() = delete; // Block unqualified name lookup +#else // ^^^ no workaround / workaround vvv + void strong_order(); +#endif // ^^^ workaround ^^^ template concept _Has_ADL = requires(_Ty1& _Left, _Ty2& _Right) { @@ -452,7 +456,11 @@ inline namespace _Cpos { } namespace _Weak_order { - void weak_order(); // Block unqualified name lookup; see GH-1374. +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void weak_order() = delete; // Block unqualified name lookup +#else // ^^^ no workaround / workaround vvv + void weak_order(); +#endif // ^^^ workaround ^^^ template concept _Has_ADL = requires(_Ty1& _Left, _Ty2& _Right) { @@ -464,7 +472,11 @@ namespace _Weak_order { requires(_Ty1& _Left, _Ty2& _Right) { static_cast(compare_three_way{}(_Left, _Right)); }; // Throughput optimization: attempting to use _STD strong_order will always select ADL strong_order here. - void strong_order(); // Block unqualified name lookup; see GH-1374. +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void strong_order() = delete; // Block unqualified name lookup +#else // ^^^ no workaround / workaround vvv + void strong_order(); +#endif // ^^^ workaround ^^^ class _Cpo { private: @@ -483,6 +495,7 @@ namespace _Weak_order { return {_St::_Three, noexcept(static_cast( compare_three_way{}(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))}; } else if constexpr (_Strong_order::_Has_ADL<_Ty1, _Ty2>) { + // throughput optimization (see above): return {_St::_Strong, noexcept(static_cast(static_cast(strong_order( _STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))}; // intentional ADL } else { @@ -554,6 +567,7 @@ namespace _Weak_order { } else if constexpr (_Strat == _St::_Three) { return static_cast(compare_three_way{}(_Left, _Right)); } else if constexpr (_Strat == _St::_Strong) { + // throughput optimization (see above): return static_cast( static_cast(strong_order(_Left, _Right))); // intentional ADL } else { @@ -568,7 +582,11 @@ inline namespace _Cpos { } namespace _Partial_order { - void partial_order(); // Block unqualified name lookup; see GH-1374. +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void partial_order() = delete; // Block unqualified name lookup +#else // ^^^ no workaround / workaround vvv + void partial_order(); +#endif // ^^^ workaround ^^^ template concept _Has_ADL = requires(_Ty1& _Left, _Ty2& _Right) { @@ -581,8 +599,13 @@ namespace _Partial_order { // Throughput optimization: attempting to use _STD weak_order // will attempt to select ADL weak_order, followed by ADL strong_order, here. - void weak_order(); // Block unqualified name lookup; see GH-1374. - void strong_order(); // Block unqualified name lookup; see GH-1374. +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void weak_order() = delete; // Block unqualified name lookup + void strong_order() = delete; // Block unqualified name lookup +#else // ^^^ no workaround / workaround vvv + void weak_order(); + void strong_order(); +#endif // ^^^ workaround ^^^ class _Cpo { private: @@ -599,9 +622,11 @@ namespace _Partial_order { return {_St::_Three, noexcept(static_cast( compare_three_way{}(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))}; } else if constexpr (_Weak_order::_Has_ADL<_Ty1, _Ty2>) { + // throughput optimization (see above): return {_St::_Weak, noexcept(static_cast(static_cast( weak_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))}; // intentional ADL } else if constexpr (_Strong_order::_Has_ADL<_Ty1, _Ty2>) { + // throughput optimization (see above): return {_St::_Strong, noexcept(static_cast(static_cast(strong_order( _STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))}; // intentional ADL } else { @@ -623,9 +648,11 @@ namespace _Partial_order { } else if constexpr (_Strat == _St::_Three) { return static_cast(compare_three_way{}(_Left, _Right)); } else if constexpr (_Strat == _St::_Weak) { + // throughput optimization (see above): return static_cast( static_cast(weak_order(_Left, _Right))); // intentional ADL } else if constexpr (_Strat == _St::_Strong) { + // throughput optimization (see above): return static_cast( static_cast(strong_order(_Left, _Right))); // intentional ADL } else { diff --git a/stl/inc/concepts b/stl/inc/concepts index 6ca7e60424..c00665e58a 100644 --- a/stl/inc/concepts +++ b/stl/inc/concepts @@ -134,7 +134,7 @@ namespace ranges { template requires _Use_ADL_swap<_Ty1, _Ty2> constexpr void operator()(_Ty1&& __t, _Ty2&& __u) const - noexcept(noexcept(swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)))) { + noexcept(noexcept(swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)))) { // intentional ADL swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)); // intentional ADL } diff --git a/stl/inc/type_traits b/stl/inc/type_traits index c346f25232..4f185d5671 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -2041,7 +2041,11 @@ inline constexpr bool is_nothrow_swappable_v = _Is_nothrow_swappable<_Ty>::value #endif // _HAS_CXX17 namespace _Has_ADL_swap_detail { - void swap(); // undefined (deliberate shadowing) +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void swap() = delete; // Block unqualified name lookup +#else // ^^^ no workaround / workaround vvv + void swap(); +#endif // ^^^ workaround ^^^ template struct _Has_ADL_swap : false_type {}; diff --git a/stl/inc/xutility b/stl/inc/xutility index 571c841fce..3f388efab0 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -402,7 +402,11 @@ concept _Destructible_object = is_object_v<_Ty> && destructible<_Ty>; namespace ranges { namespace _Iter_move { - void iter_move(); // Block unqualified name lookup +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void iter_move() = delete; // Block unqualified name lookup +#else // ^^^ no workaround / workaround vvv + void iter_move(); +#endif // ^^^ workaround ^^^ // clang-format off template @@ -2089,7 +2093,11 @@ namespace ranges { concept _Should_range_access = is_lvalue_reference_v<_Rng> || enable_borrowed_range>; namespace _Begin { - void begin(); // Block unqualified name lookup +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void begin() = delete; // Block unqualified name lookup +#else // ^^^ no workaround / workaround vvv + void begin(); +#endif // ^^^ workaround ^^^ template concept _Has_member = requires(_Ty __t) { @@ -2154,7 +2162,11 @@ namespace ranges { using iterator_t = decltype(_RANGES begin(_STD declval<_Ty&>())); namespace _End { - void end(); // Block unqualified name lookup +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void end() = delete; // Block unqualified name lookup +#else // ^^^ no workaround / workaround vvv + void end(); +#endif // ^^^ workaround ^^^ template concept _Has_member = requires(_Ty __t) { @@ -2494,7 +2506,11 @@ namespace ranges { } namespace _Rbegin { - void rbegin(); // Block unqualified name lookup +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void rbegin() = delete; // Block unqualified name lookup +#else // ^^^ no workaround / workaround vvv + void rbegin(); +#endif // ^^^ workaround ^^^ template concept _Has_member = requires(_Ty __t) { @@ -2559,7 +2575,11 @@ namespace ranges { } namespace _Rend { - void rend(); // Block unqualified name lookup +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void rend() = delete; // Block unqualified name lookup +#else // ^^^ no workaround / workaround vvv + void rend(); +#endif // ^^^ workaround ^^^ template concept _Has_member = requires(_Ty __t) { @@ -2678,7 +2698,11 @@ namespace ranges { inline constexpr bool disable_sized_range = false; namespace _Size { - void size(); // Block unqualified name lookup +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void size() = delete; // Block unqualified name lookup +#else // ^^^ no workaround / workaround vvv + void size(); +#endif // ^^^ workaround ^^^ template concept _Has_member = (!disable_sized_range<_UnCV>) // diff --git a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp index 18b8c52348..ab120f23db 100644 --- a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp @@ -1886,48 +1886,26 @@ STATIC_ASSERT(ranges::viewable_range>); STATIC_ASSERT(ranges::viewable_range const>); namespace poison_pill_test { - static int some_int = 42; - template - int* begin(T&) { - return &some_int; - } + int* begin(T&); template - int const* begin(T const&) { - return &some_int; - } + int const* begin(T const&); template - int* end(T&) { - return &some_int + 1; - } + int* end(T&); template - int const* end(T const&) { - return &some_int + 1; - } + int const* end(T const&); template - auto rbegin(T&) { - return std::reverse_iterator{&some_int + 1}; - } + std::reverse_iterator rbegin(T&); template - auto rbegin(T const&) { - return std::reverse_iterator{&some_int + 1}; - } + std::reverse_iterator rbegin(T const&); template - auto rend(T&) { - return std::reverse_iterator{&some_int}; - } + std::reverse_iterator rend(T&); template - auto rend(T const&) { - return std::reverse_iterator{&some_int}; - } + std::reverse_iterator rend(T const&); template - auto size(T&) { - return std::size_t{1}; - } + std::size_t size(T&); template - auto size(T const&) { - return std::size_t{1}; - } + std::size_t size(T const&); struct some_type {}; diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 74c82778cf..6d9a87b427 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -30,7 +30,7 @@ STATIC_ASSERT(__cpp_lib_adaptor_iterator_pair_constructor == 202106L); STATIC_ASSERT(__cpp_lib_addressof_constexpr == 201603L); #endif -#if _HAS_CXX20 && defined(__cpp_lib_concepts) +#if _HAS_CXX20 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 #ifndef __cpp_lib_algorithm_iterator_requirements #error __cpp_lib_algorithm_iterator_requirements is not defined #elif __cpp_lib_algorithm_iterator_requirements != 202207L From 05ca7c3fb13da2c5e6a5617d6d8ee6197c96de35 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 29 Nov 2022 16:13:27 -0800 Subject: [PATCH 3/3] Remove "const east" changes in unrelated code --- .../P0896R4_ranges_range_machinery/test.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp index ab120f23db..a69f05bec8 100644 --- a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp @@ -34,7 +34,7 @@ STATIC_ASSERT(std::same_as, std::size_t>); // GH-2358: : path's comparison operators are IF-NDR static_assert(ranges::range); -static_assert(ranges::range); +static_assert(ranges::range); template concept Decayed = std::same_as, T>; @@ -1088,7 +1088,7 @@ STATIC_ASSERT(test_cdata const&, int*>()); #endif // C++20 using valarray_int_iterator = decltype(std::begin(std::declval&>())); -using const_valarray_int_iterator = decltype(std::begin(std::declval const&>())); +using const_valarray_int_iterator = decltype(std::begin(std::declval&>())); STATIC_ASSERT(test_begin>()); STATIC_ASSERT(test_end>()); STATIC_ASSERT(test_cbegin>()); @@ -1631,7 +1631,7 @@ struct badsized_range : Base { // size() launches the missiles. static_assert(always_false); } - [[noreturn]] friend int size(badsized_range const&) { + [[noreturn]] friend int size(const badsized_range&) { static_assert(always_false); } }; @@ -1670,9 +1670,9 @@ STATIC_ASSERT(!std::is_base_of_v or enable_view is never true STATIC_ASSERT(ranges::enable_view); STATIC_ASSERT(!ranges::enable_view); -STATIC_ASSERT(!ranges::enable_view); +STATIC_ASSERT(!ranges::enable_view); STATIC_ASSERT(!ranges::enable_view); -STATIC_ASSERT(!ranges::enable_view); +STATIC_ASSERT(!ranges::enable_view); // Verify that the derived-from-view_interface mechanism can handle uses of incomplete types whenever possible struct incomplet; @@ -1852,7 +1852,7 @@ constexpr bool complicated_algorithm_test() { // Regression test for DevCom-739010 (aka VSO-985597) // https://developercommunity.visualstudio.com/content/problem/739010/meow.html -// which allows overload resolution to prefer a hidden friend `T const&` overload of `begin` +// which allows overload resolution to prefer a hidden friend `const T&` overload of `begin` // for an rvalue `T` over the deleted `begin(T&&)` instantiated from the poison pill. template struct bad_string_view { @@ -1993,13 +1993,13 @@ namespace closure { constexpr arg(arg&) { static_assert(Allowed == GLValueKind::lvalue); } - constexpr arg(arg const&) { + constexpr arg(const arg&) { static_assert(Allowed == GLValueKind::const_lvalue); } constexpr arg(arg&&) { static_assert(Allowed == GLValueKind::xvalue); } - constexpr arg(arg const&&) { + constexpr arg(const arg&&) { static_assert(Allowed == GLValueKind::const_xvalue); }